From ac99cbb665688e73ee9aa4b7fc46ac2161f14e48 Mon Sep 17 00:00:00 2001 From: Michal Skogemann Date: Wed, 25 Jun 2025 15:54:33 +0200 Subject: [PATCH] Add scheduled task dispatcher --- README.md | 16 ++++++++ .../Commands/DispatchDueTasksCommand.php | 34 +++++++++++++++++ src/TasksServiceProvider.php | 20 ++++++---- tests/DispatchDueTasksCommandTest.php | 37 +++++++++++++++++++ tests/Jobs/DummyJob.php | 26 +++++++++++++ 5 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 src/Console/Commands/DispatchDueTasksCommand.php create mode 100644 tests/DispatchDueTasksCommandTest.php create mode 100644 tests/Jobs/DummyJob.php diff --git a/README.md b/README.md index 46f888e..3726dd8 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,24 @@ $user->tasks()->completed()->get(); // Get all tasks that are completed and have a due date in the future $user->tasks()->completed()->future()->get(); + +// Schedule a job for a task +$user->addTask([ + 'name' => 'Cleanup', + 'job' => \App\Jobs\CleanupJob::class, + 'job_data' => json_encode(['force' => true]), + 'due_date' => now()->addMinutes(10), +]); +``` + +Run the dispatcher command manually if needed: + +```bash +php artisan tasks:dispatch ``` +When `TASKS_AUTO_SCHEDULE` is enabled (the default), this command is automatically scheduled to run every minute. + ### Testing (Not implemented yet) diff --git a/src/Console/Commands/DispatchDueTasksCommand.php b/src/Console/Commands/DispatchDueTasksCommand.php new file mode 100644 index 0000000..22e3e46 --- /dev/null +++ b/src/Console/Commands/DispatchDueTasksCommand.php @@ -0,0 +1,34 @@ +whereNotNull('job') + ->whereNotNull('due_date') + ->where('due_date', '<=', now()) + ->get(); + + foreach ($tasks as $task) { + $job = new $task->job($task->job_data); + Bus::dispatch($job); + + $task->status = Task::STATUS_RUNNING; + $task->save(); + } + + $this->info($tasks->count() . ' tasks dispatched.'); + + return Command::SUCCESS; + } +} diff --git a/src/TasksServiceProvider.php b/src/TasksServiceProvider.php index 2f2ffdb..68da132 100644 --- a/src/TasksServiceProvider.php +++ b/src/TasksServiceProvider.php @@ -2,7 +2,9 @@ namespace Michal78\Tasks; +use Illuminate\Console\Scheduling\Schedule; use Illuminate\Support\ServiceProvider; +use Michal78\Tasks\Console\Commands\DispatchDueTasksCommand; class TasksServiceProvider extends ServiceProvider { @@ -22,13 +24,17 @@ public function boot(): void __DIR__.'/../config/config.php' => config_path('laravel-tasks.php'), ], 'config'); - // Publishing the translation files. - /*$this->publishes([ - __DIR__.'/../resources/lang' => resource_path('lang/vendor/laravel-tasks'), - ], 'lang');*/ - - // Registering package commands. - // $this->commands([]); + // Register package command + $this->commands([ + DispatchDueTasksCommand::class, + ]); + + if (config('laravel-tasks.auto_schedule')) { + $this->app->booted(function () { + $schedule = $this->app->make(Schedule::class); + $schedule->command('tasks:dispatch')->everyMinute(); + }); + } } } diff --git a/tests/DispatchDueTasksCommandTest.php b/tests/DispatchDueTasksCommandTest.php new file mode 100644 index 0000000..39035b8 --- /dev/null +++ b/tests/DispatchDueTasksCommandTest.php @@ -0,0 +1,37 @@ + 'Test']); + + $dueTask = $user->addTask([ + 'name' => 'Due', + 'job' => DummyJob::class, + 'job_data' => json_encode(['foo' => 'bar']), + 'due_date' => now()->subMinute(), + ]); + + $futureTask = $user->addTask([ + 'name' => 'Future', + 'job' => DummyJob::class, + 'due_date' => now()->addHour(), + ]); + + Artisan::call('tasks:dispatch'); + + Queue::assertPushed(DummyJob::class, 1); + $this->assertEquals(Task::STATUS_RUNNING, $dueTask->fresh()->status); + $this->assertEquals(Task::STATUS_PENDING, $futureTask->fresh()->status); + } +} diff --git a/tests/Jobs/DummyJob.php b/tests/Jobs/DummyJob.php new file mode 100644 index 0000000..b5dabc0 --- /dev/null +++ b/tests/Jobs/DummyJob.php @@ -0,0 +1,26 @@ +data = $data; + } + + public function handle(): void + { + // no-op + } +}