diff --git a/app/Jobs/CheckMissingDatabaseBackupsJob.php b/app/Jobs/CheckMissingDatabaseBackupsJob.php index 61e7ced397..ca91156574 100644 --- a/app/Jobs/CheckMissingDatabaseBackupsJob.php +++ b/app/Jobs/CheckMissingDatabaseBackupsJob.php @@ -18,6 +18,14 @@ class CheckMissingDatabaseBackupsJob implements ShouldBeEncrypted, ShouldBeUniqu { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public $timeout = 1800; + + /** + * Releases the unique lock of a killed worker after one run (the timeout), so the next hourly run is not + * blocked until the queue retry_after. + */ + public int $uniqueFor = 1800; + public function handle(): void { ScheduledDatabaseBackup::query() diff --git a/app/Jobs/CleanupInstanceStuffsJob.php b/app/Jobs/CleanupInstanceStuffsJob.php index 85c39a8e08..87a95d547f 100644 --- a/app/Jobs/CleanupInstanceStuffsJob.php +++ b/app/Jobs/CleanupInstanceStuffsJob.php @@ -23,6 +23,12 @@ class CleanupInstanceStuffsJob implements ShouldBeEncrypted, ShouldBeUnique, Sho public $timeout = 60; + /** + * Releases the unique lock of a killed worker after one run (the timeout), so the next run every one or + * two minutes is not blocked until the queue retry_after. + */ + public int $uniqueFor = 60; + public function __construct() {} public function middleware(): array diff --git a/app/Jobs/CleanupOrphanedPreviewContainersJob.php b/app/Jobs/CleanupOrphanedPreviewContainersJob.php index d3286699fa..46396c7f0f 100644 --- a/app/Jobs/CleanupOrphanedPreviewContainersJob.php +++ b/app/Jobs/CleanupOrphanedPreviewContainersJob.php @@ -30,6 +30,12 @@ class CleanupOrphanedPreviewContainersJob implements ShouldBeEncrypted, ShouldBe public $timeout = 600; // 10 minutes max + /** + * Releases the unique lock of a killed worker after one run (the timeout), instead of after the queue + * retry_after, so the next daily run is not blocked. + */ + public int $uniqueFor = 600; + public function __construct() {} public function middleware(): array diff --git a/tests/Feature/ScheduledInstanceJobsUniqueLockTest.php b/tests/Feature/ScheduledInstanceJobsUniqueLockTest.php new file mode 100644 index 0000000000..4ee8d66780 --- /dev/null +++ b/tests/Feature/ScheduledInstanceJobsUniqueLockTest.php @@ -0,0 +1,33 @@ +set('cache.default', 'array'); + Queue::fake(); +}); + +dataset('scheduled instance jobs', [ + 'orphaned preview containers cleanup' => [CleanupOrphanedPreviewContainersJob::class, 600], + 'instance cleanup' => [CleanupInstanceStuffsJob::class, 60], + 'missing database backups check' => [CheckMissingDatabaseBackupsJob::class, 1800], +]); + +it('does not queue the job again while its unique lock is held', function (string $jobClass, int $lockSeconds) { + $jobClass::dispatch(); + $this->travel($lockSeconds - 1)->seconds(); + $jobClass::dispatch(); + + Queue::assertPushed($jobClass, 1); +})->with('scheduled instance jobs'); + +it('queues the job again after a unique lock left by a killed worker expires', function (string $jobClass, int $lockSeconds) { + $jobClass::dispatch(); + $this->travel($lockSeconds + 1)->seconds(); + $jobClass::dispatch(); + + Queue::assertPushed($jobClass, 2); +})->with('scheduled instance jobs');