mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-14 00:33:44 -04:00
The scheduled job manager checked every enabled schedule each minute and evaluated its cron expression in PHP. On Coolify Cloud one run took more than 60 seconds, so runs overlapped and minutes were skipped. Each schedule now stores its next due time: - next_run_at on scheduled database backups, scheduled tasks, and volume backups, and docker_cleanup_next_run_at on server settings (UTC, indexed) - model hooks calculate it when a schedule is created or its frequency or enabled flag changes; a server timezone change or a move to another server calculates it again for the affected schedules The `scheduled:dispatch` command runs the manager every minute from the scheduler, not from a queue. It selects only due rows and claims each occurrence with an atomic update of next_run_at, together with its delivery record, so parallel runs on several nodes never dispatch it twice. - database and volume backups run once when they are late; tasks and Docker cleanups more than 10 minutes late are logged as missed - a local time that occurs two times when the clocks go back runs once - the migration continues each schedule after its last recorded occurrence and drops scheduled_job_states Show the next run, in the server timezone, on the database backup, scheduled task, volume backup, and Docker cleanup pages, or "Invalid frequency" when the frequency cannot be calculated. scheduled:diagnostics now lists overdue schedules and open deliveries. Remove workarounds that are no longer needed: the queue overlap lock and its stale-lock repair, the catch-up window, and debug-only logs.
72 lines
2.2 KiB
PHP
72 lines
2.2 KiB
PHP
<?php
|
|
|
|
use App\Actions\Database\StartDatabase;
|
|
use App\Actions\Database\StartDatabaseProxy;
|
|
use App\Actions\Service\StartService;
|
|
use App\Jobs\DatabaseBackupJob;
|
|
use App\Models\ScheduledDatabaseBackup;
|
|
|
|
describe('deployment_queue helper', function () {
|
|
test('uses the high queue on self-hosted', function () {
|
|
config(['constants.coolify.self_hosted' => true]);
|
|
|
|
expect(deployment_queue())->toBe('high');
|
|
});
|
|
|
|
test('uses the deployments queue on cloud', function () {
|
|
config(['constants.coolify.self_hosted' => false]);
|
|
|
|
expect(deployment_queue())->toBe('deployments');
|
|
});
|
|
});
|
|
|
|
describe('crons_queue helper', function () {
|
|
test('uses the high queue on self-hosted', function () {
|
|
config(['constants.coolify.self_hosted' => true]);
|
|
|
|
expect(crons_queue())->toBe('high');
|
|
});
|
|
|
|
test('uses the crons queue on cloud', function () {
|
|
config(['constants.coolify.self_hosted' => false]);
|
|
|
|
expect(crons_queue())->toBe('crons');
|
|
});
|
|
});
|
|
|
|
describe('start action job routing', function () {
|
|
test('routes to the deployments queue on cloud', function (string $actionClass) {
|
|
config(['constants.coolify.self_hosted' => false]);
|
|
|
|
expect($actionClass::makeJob()->queue)->toBe('deployments');
|
|
})->with([
|
|
StartDatabase::class,
|
|
StartDatabaseProxy::class,
|
|
StartService::class,
|
|
]);
|
|
|
|
test('routes to the high queue on self-hosted', function (string $actionClass) {
|
|
config(['constants.coolify.self_hosted' => true]);
|
|
|
|
expect($actionClass::makeJob()->queue)->toBe('high');
|
|
})->with([
|
|
StartDatabase::class,
|
|
StartDatabaseProxy::class,
|
|
StartService::class,
|
|
]);
|
|
});
|
|
|
|
describe('scheduled job routing', function () {
|
|
test('scheduled jobs use the crons queue on cloud', function () {
|
|
config(['constants.coolify.self_hosted' => false]);
|
|
|
|
expect((new DatabaseBackupJob(new ScheduledDatabaseBackup))->queue)->toBe('crons');
|
|
});
|
|
|
|
test('scheduled jobs use the high queue on self-hosted', function () {
|
|
config(['constants.coolify.self_hosted' => true]);
|
|
|
|
expect((new DatabaseBackupJob(new ScheduledDatabaseBackup))->queue)->toBe('high');
|
|
});
|
|
});
|