diff --git a/modules/flysystem_migrate/flysystem_migrate.module b/modules/flysystem_migrate/flysystem_migrate.module
index fc43585..2b52a03 100644
--- a/modules/flysystem_migrate/flysystem_migrate.module
+++ b/modules/flysystem_migrate/flysystem_migrate.module
@@ -5,8 +5,8 @@
  * Hook implementations for the Flysystem Migrate module.
  */
 
-use Drupal\flysystem_migrate\MigrationBatchProcessor;
-use Drupal\flysystem_migrate\MigrationBatchStorage;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\flysystem_migrate\Hook\FlysystemMigrateHooks;
 
 /**
  * Implements hook_cron().
@@ -16,23 +16,7 @@ use Drupal\flysystem_migrate\MigrationBatchStorage;
  * batch_size — not a time budget — determines how many files get processed
  * per run.
  */
+#[LegacyHook]
 function flysystem_migrate_cron(): void {
-  $lock = \Drupal::lock();
-  if (!$lock->acquire('flysystem_migrate_cron')) {
-    return;
-  }
-
-  try {
-    /** @var \Drupal\flysystem_migrate\MigrationBatchStorage $storage */
-    $storage = \Drupal::service(MigrationBatchStorage::class);
-    /** @var \Drupal\flysystem_migrate\MigrationBatchProcessor $processor */
-    $processor = \Drupal::service(MigrationBatchProcessor::class);
-
-    foreach ($storage->loadActive() as $batch) {
-      $processor->processBatch((int) $batch->id, (int) $batch->batch_size);
-    }
-  }
-  finally {
-    $lock->release('flysystem_migrate_cron');
-  }
+  \Drupal::service(FlysystemMigrateHooks::class)->cron();
 }
diff --git a/modules/flysystem_migrate/flysystem_migrate.services.yml b/modules/flysystem_migrate/flysystem_migrate.services.yml
index cdb3e62..56bb67b 100644
--- a/modules/flysystem_migrate/flysystem_migrate.services.yml
+++ b/modules/flysystem_migrate/flysystem_migrate.services.yml
@@ -50,3 +50,7 @@ services:
       - '@queue'
       - '@entity_type.manager'
       - '@logger.channel.flysystem'
+
+  Drupal\flysystem_migrate\Hook\FlysystemMigrateHooks:
+    class: Drupal\flysystem_migrate\Hook\FlysystemMigrateHooks
+    autowire: true
diff --git a/modules/flysystem_migrate/src/Hook/FlysystemMigrateHooks.php b/modules/flysystem_migrate/src/Hook/FlysystemMigrateHooks.php
new file mode 100644
index 0000000..69a5eb7
--- /dev/null
+++ b/modules/flysystem_migrate/src/Hook/FlysystemMigrateHooks.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Drupal\flysystem_migrate\Hook;
+
+use Drupal\flysystem_migrate\MigrationBatchProcessor;
+use Drupal\flysystem_migrate\MigrationBatchStorage;
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for flysystem_migrate.
+ */
+class FlysystemMigrateHooks {
+
+  /**
+   * Implements hook_cron().
+   *
+   * Drives batch processing directly rather than relying on core's per-queue
+   * cron mechanism (see FileMigrationWorker), so each batch's own configured
+   * batch_size — not a time budget — determines how many files get processed
+   * per run.
+   */
+  #[Hook('cron')]
+  public function cron(): void {
+    $lock = \Drupal::lock();
+    if (!$lock->acquire('flysystem_migrate_cron')) {
+      return;
+    }
+    try {
+      /** @var \Drupal\flysystem_migrate\MigrationBatchStorage $storage */
+      $storage = \Drupal::service(MigrationBatchStorage::class);
+      /** @var \Drupal\flysystem_migrate\MigrationBatchProcessor $processor */
+      $processor = \Drupal::service(MigrationBatchProcessor::class);
+      foreach ($storage->loadActive() as $batch) {
+        $processor->processBatch((int) $batch->id, (int) $batch->batch_size);
+      }
+    } finally {
+      $lock->release('flysystem_migrate_cron');
+    }
+  }
+
+}
