diff --git a/.github/workflows/tests-postgres.yml b/.github/workflows/tests-postgres.yml index b4d2caf5..31ae0508 100644 --- a/.github/workflows/tests-postgres.yml +++ b/.github/workflows/tests-postgres.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ "8.0", "8.1", "8.2", "8.3", "8.4" ] + php: [ "8.3", "8.4" ] name: "PHP ${{ matrix.php }}" runs-on: ubuntu-latest diff --git a/.github/workflows/tests-sqlite.yml b/.github/workflows/tests-sqlite.yml index 822ab746..35c2bcf5 100644 --- a/.github/workflows/tests-sqlite.yml +++ b/.github/workflows/tests-sqlite.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ "8.0", "8.1", "8.2", "8.3", "8.4" ] + php: [ "8.3", "8.4" ] name: "PHP ${{ matrix.php }}" runs-on: ubuntu-latest diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6ce154a9..97d4bafa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ "8.0", "8.1", "8.2", "8.3", "8.4" ] + php: [ "8.3", "8.4" ] name: "PHP ${{ matrix.php }}" runs-on: ubuntu-latest diff --git a/README.md b/README.md index 5f189def..d9e60da8 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,11 @@ use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; + use romanzipp\QueueMonitor\Traits\IsMonitored; // <--- +use romanzipp\QueueMonitor\Contracts\MonitoredJobContract; // <--- -class ExampleJob implements ShouldQueue +class ExampleJob implements ShouldQueue, MonitoredJobContract { use Dispatchable; use InteractsWithQueue; diff --git a/composer.json b/composer.json index 6f4f2465..0483cd7f 100644 --- a/composer.json +++ b/composer.json @@ -11,18 +11,18 @@ } ], "require": { - "php": "^8.0", + "php": "^8.3", "ext-json": "*", "ext-mbstring": "*", - "illuminate/database": ">=5.5", - "illuminate/queue": ">=5.5", - "illuminate/support": ">=5.5", + "illuminate/database": ">=11.0", + "illuminate/queue": ">=11.0", + "illuminate/support": ">=11.0", "nesbot/carbon": "^2.0|^3.0" }, "require-dev": { "doctrine/dbal": "^3.1|^4.2", "friendsofphp/php-cs-fixer": "^3.0", - "laravel/framework": ">=5.5", + "laravel/framework": ">=11.0", "mockery/mockery": "^1.3.2", "orchestra/testbench": ">=3.8", "phpstan/phpstan": "^0.12.99|^1.0|^2.1", diff --git a/config/queue-monitor.php b/config/queue-monitor.php index 85e1ecbd..a589cb28 100644 --- a/config/queue-monitor.php +++ b/config/queue-monitor.php @@ -13,9 +13,6 @@ */ 'model' => \romanzipp\QueueMonitor\Models\Monitor::class, - // Determined if the queued jobs should be monitored - 'monitor_queued_jobs' => true, - // Specify the max character length to use for storing exception backtraces. 'db_max_length_exception' => 4294967295, 'db_max_length_exception_message' => 65535, diff --git a/src/Providers/QueueMonitorProvider.php b/src/Providers/QueueMonitorProvider.php index 5a7446a1..e1fe7309 100644 --- a/src/Providers/QueueMonitorProvider.php +++ b/src/Providers/QueueMonitorProvider.php @@ -2,11 +2,8 @@ namespace romanzipp\QueueMonitor\Providers; -use Illuminate\Queue\Events\JobExceptionOccurred; -use Illuminate\Queue\Events\JobFailed; -use Illuminate\Queue\Events\JobProcessed; -use Illuminate\Queue\Events\JobProcessing; -use Illuminate\Queue\Events\JobQueued; +use Illuminate\Config\Repository; +use Illuminate\Queue\Events as QueueEvents; use Illuminate\Queue\QueueManager; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Route; @@ -21,6 +18,15 @@ class QueueMonitorProvider extends ServiceProvider { public function boot(): void { + /** @var \Illuminate\Config\Repository $config */ + $config = $this->app['config']; + + /** @var \Illuminate\Events\Dispatcher $events */ + $events = $this->app['events']; + + /** @var \Illuminate\Queue\QueueManager $queueManager */ + $queueManager = $this->app->make(QueueManager::class); + if ($this->app->runningInConsole()) { $this->publishes([ __DIR__ . '/../../config/queue-monitor.php' => config_path('queue-monitor.php'), @@ -48,84 +54,94 @@ public function boot(): void ]); } - $this->loadViewsFrom( - __DIR__ . '/../../views', - 'queue-monitor' - ); + $this->loadViewsFrom(__DIR__ . '/../../views', 'queue-monitor'); - if (config('queue-monitor.ui.enabled')) { - Route::group($this->buildRouteGroupConfig(), function () { + if ($config->boolean('queue-monitor.ui.enabled', false)) { + Route::group(self::buildRouteGroupConfig($config), function () { $this->loadRoutesFrom(__DIR__ . '/../../routes/queue-monitor.php'); }); } - // listen to JobQueued event - if (config('queue-monitor.monitor_queued_jobs', true)) { - /** - * If the project uses Horizon, we will listen to the JobPushed event, - * because Horizon fires JobPushed event when the job is queued or retry the job again from its UI. - * - * @see https://laravel.com/docs/horizon - */ - if (class_exists('Laravel\Horizon\Events\JobPushed')) { - Event::listen('Laravel\Horizon\Events\JobPushed', function ($event) { - QueueMonitor::handleJobPushed($event); - }); - } else { - Event::listen(JobQueued::class, function (JobQueued $event) { - QueueMonitor::handleJobQueued($event); - }); - } + // Listen to queue job events + + /** + * If the project uses Horizon, we will listen to the JobPushed event, + * because Horizon fires JobPushed event when the job is queued or retry the job again from its UI. + * + * @see https://laravel.com/docs/horizon + */ + if (class_exists('Laravel\Horizon\Events\JobPushed')) { + $events->listen('Laravel\Horizon\Events\JobPushed', function ($event) { + QueueMonitor::handleJobPushed($event); + }); + } else { + $events->listen(QueueEvents\JobQueued::class, function (QueueEvents\JobQueued $event) { + QueueMonitor::handleJobQueued($event); + }); } - // listen to other job events - - /** @var QueueManager $manager */ - $manager = app(QueueManager::class); - - $manager->before(static function (JobProcessing $event) { + $queueManager->before(static function (QueueEvents\JobProcessing $event) { QueueMonitor::handleJobProcessing($event); }); - $manager->after(static function (JobProcessed $event) { + $queueManager->after(static function (QueueEvents\JobProcessed $event) { QueueMonitor::handleJobProcessed($event); }); - $manager->failing(static function (JobFailed $event) { + $queueManager->failing(static function (QueueEvents\JobFailed $event) { QueueMonitor::handleJobFailed($event); }); - $manager->exceptionOccurred(static function (JobExceptionOccurred $event) { + $queueManager->exceptionOccurred(static function (QueueEvents\JobExceptionOccurred $event) { QueueMonitor::handleJobExceptionOccurred($event); }); + + $this->app['events']->listen([ + QueueEvents\JobExceptionOccurred::class, + QueueEvents\JobFailed::class, + QueueEvents\JobPopped::class, + QueueEvents\JobPopping::class, + QueueEvents\JobProcessed::class, + QueueEvents\JobProcessing::class, + QueueEvents\JobQueued::class, + QueueEvents\JobQueueing::class, + QueueEvents\JobReleasedAfterException::class, + QueueEvents\JobRetryRequested::class, + QueueEvents\JobTimedOut::class, + QueueEvents\Looping::class, + QueueEvents\QueueBusy::class, + QueueEvents\WorkerStopping::class, + ], function ($event) { + // dump(get_class($event)); + }); } /** * @return array */ - private function buildRouteGroupConfig(): array + public static function buildRouteGroupConfig(Repository $config): array { - $config = config('queue-monitor.ui.route'); + $routeConfig = $config->array('queue-monitor.ui.route'); - if ( ! isset($config['middleware'])) { - $config['middleware'] = []; + if ( ! isset($routeConfig['middleware'])) { + $routeConfig['middleware'] = []; } - $config['middleware'][] = CheckQueueMonitorUiConfig::class; + $routeConfig['middleware'][] = CheckQueueMonitorUiConfig::class; - return $config; + return $routeConfig; } public function register(): void { - /** @phpstan-ignore-next-line */ - if ( ! $this->app->configurationIsCached()) { - $this->mergeConfigFrom( - __DIR__ . '/../../config/queue-monitor.php', - 'queue-monitor' - ); - } + /** @var \Illuminate\Config\Repository $config */ + $config = $this->app['config']; + + $this->mergeConfigFrom( + __DIR__ . '/../../config/queue-monitor.php', + 'queue-monitor' + ); - QueueMonitor::$model = config('queue-monitor.model') ?: Monitor::class; + QueueMonitor::$model = $config->get('queue-monitor.model') ?: Monitor::class; } } diff --git a/src/Services/QueueMonitor.php b/src/Services/QueueMonitor.php index 28c6676a..39833393 100644 --- a/src/Services/QueueMonitor.php +++ b/src/Services/QueueMonitor.php @@ -5,11 +5,7 @@ use Illuminate\Container\Container; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Queue\Job as JobContract; -use Illuminate\Queue\Events\JobExceptionOccurred; -use Illuminate\Queue\Events\JobFailed; -use Illuminate\Queue\Events\JobProcessed; -use Illuminate\Queue\Events\JobProcessing; -use Illuminate\Queue\Events\JobQueued; +use Illuminate\Queue\Events as QueueEvents; use Illuminate\Support\Carbon; use romanzipp\QueueMonitor\Enums\MonitorStatus; use romanzipp\QueueMonitor\Models\Contracts\MonitorContract; @@ -17,7 +13,7 @@ class QueueMonitor { - private const TIMESTAMP_EXACT_FORMAT = 'Y-m-d H:i:s.u'; + private const string TIMESTAMP_EXACT_FORMAT = 'Y-m-d H:i:s.u'; public static string $model; @@ -31,14 +27,7 @@ public static function getModel(): MonitorContract return new self::$model(); } - /** - * Handle Job Queued. - * - * @param JobQueued $event - * - * @return void - */ - public static function handleJobQueued(JobQueued $event): void + public static function handleJobQueued(QueueEvents\JobQueued $event): void { self::jobQueued($event); } @@ -53,50 +42,22 @@ public static function handleJobPushed($event): void self::jobPushed($event); } - /** - * Handle Job Processing. - * - * @param JobProcessing $event - * - * @return void - */ - public static function handleJobProcessing(JobProcessing $event): void + public static function handleJobProcessing(QueueEvents\JobProcessing $event): void { self::jobStarted($event->job); } - /** - * Handle Job Processed. - * - * @param JobProcessed $event - * - * @return void - */ - public static function handleJobProcessed(JobProcessed $event): void + public static function handleJobProcessed(QueueEvents\JobProcessed $event): void { self::jobFinished($event->job, MonitorStatus::SUCCEEDED); } - /** - * Handle Job Failing. - * - * @param JobFailed $event - * - * @return void - */ - public static function handleJobFailed(JobFailed $event): void + public static function handleJobFailed(QueueEvents\JobFailed $event): void { self::jobFinished($event->job, MonitorStatus::FAILED, $event->exception); } - /** - * Handle Job Exception Occurred. - * - * @param JobExceptionOccurred $event - * - * @return void - */ - public static function handleJobExceptionOccurred(JobExceptionOccurred $event): void + public static function handleJobExceptionOccurred(QueueEvents\JobExceptionOccurred $event): void { self::jobFinished($event->job, MonitorStatus::FAILED, $event->exception); } @@ -120,11 +81,11 @@ public static function getJobId(JobContract $job): string /** * Start Queue Monitoring for Job. * - * @param JobQueued $event + * @param QueueEvents\JobQueued $event * * @return void */ - protected static function jobQueued(JobQueued $event): void + protected static function jobQueued(QueueEvents\JobQueued $event): void { if ( ! self::shouldBeMonitored($event->job)) { return; diff --git a/src/Traits/IsMonitored.php b/src/Traits/IsMonitored.php index 4134f161..a9d55b0a 100644 --- a/src/Traits/IsMonitored.php +++ b/src/Traits/IsMonitored.php @@ -15,14 +15,14 @@ trait IsMonitored * * @var int|null */ - private $progressLastUpdated; + private ?int $progressLastUpdated; /** * Internal variable used for tracking chunking progress. * * @var int */ - private $progressCurrentChunk = 0; + private int $progressCurrentChunk = 0; /** * Update progress. diff --git a/tests/MonitorRetryTest.php b/tests/MonitorRetryTest.php index da81fc7f..c30329b6 100644 --- a/tests/MonitorRetryTest.php +++ b/tests/MonitorRetryTest.php @@ -13,11 +13,12 @@ class MonitorRetryTest extends DatabaseTestCase public function setUp(): void { parent::setUp(); + } - config([ - 'queue-monitor.ui.enabled' => true, - 'queue-monitor.ui.allow_retry' => true, - ]); + protected function defineEnvironment($app): void + { + $app['config']->set('queue-monitor.ui.enabled', true); + $app['config']->set('queue-monitor.ui.allow_retry', true); } protected function tearDown(): void @@ -31,11 +32,6 @@ protected function tearDown(): void public function testRetryFailedMonitor(): void { - config([ - 'queue-monitor.ui.enabled' => true, - 'queue-monitor.ui.allow_retry' => true, - ]); - $this ->dispatch(new MonitoredFailingJob()) ->assertDispatched(MonitoredFailingJob::class) diff --git a/tests/RoutesTest.php b/tests/RoutesTest.php index f881f3a8..fb966e1d 100644 --- a/tests/RoutesTest.php +++ b/tests/RoutesTest.php @@ -15,6 +15,12 @@ public function setUp(): void $this->withExceptionHandling(); } + protected function defineEnvironment($app): void + { + $app['config']->set('queue-monitor.ui.enabled', true); + $app['config']->set('queue-monitor.ui.allow_retry', true); + } + /* *-------------------------------------------------------------------------- * Index