refactor(jobs): split task skip checks into critical and runtime phases

Move expensive runtime checks (service/application status) after cron
validation to avoid running them for tasks that aren't due. Critical
checks (orphans, infrastructure) remain in first phase.

Also fix database heading parameters to be built from the model.
This commit is contained in:
Andras Bacsai 2026-02-28 18:37:51 +01:00
parent 31555f9e8a
commit 9a4b4280be
2 changed files with 39 additions and 16 deletions

View file

@ -214,10 +214,12 @@ private function processScheduledTasks(): void
foreach ($tasks as $task) {
try {
$server = $task->server();
$skipReason = $this->getTaskSkipReason($task, $server);
if ($skipReason !== null) {
// Phase 1: Critical checks (always — cheap, handles orphans and infra issues)
$criticalSkip = $this->getTaskCriticalSkipReason($task, $server);
if ($criticalSkip !== null) {
$this->skippedCount++;
$this->logSkip('task', $skipReason, [
$this->logSkip('task', $criticalSkip, [
'task_id' => $task->id,
'task_name' => $task->name,
'team_id' => $server?->team_id,
@ -237,16 +239,31 @@ private function processScheduledTasks(): void
$frequency = VALID_CRON_STRINGS[$frequency];
}
if ($this->shouldRunNow($frequency, $serverTimezone, "scheduled-task:{$task->id}")) {
ScheduledTaskJob::dispatch($task);
$this->dispatchedCount++;
Log::channel('scheduled')->info('Task dispatched', [
if (! $this->shouldRunNow($frequency, $serverTimezone, "scheduled-task:{$task->id}")) {
continue;
}
// Phase 2: Runtime checks (only when cron is due — avoids noise for stopped resources)
$runtimeSkip = $this->getTaskRuntimeSkipReason($task);
if ($runtimeSkip !== null) {
$this->skippedCount++;
$this->logSkip('task', $runtimeSkip, [
'task_id' => $task->id,
'task_name' => $task->name,
'team_id' => $server->team_id,
'server_id' => $server->id,
]);
continue;
}
ScheduledTaskJob::dispatch($task);
$this->dispatchedCount++;
Log::channel('scheduled')->info('Task dispatched', [
'task_id' => $task->id,
'task_name' => $task->name,
'team_id' => $server->team_id,
'server_id' => $server->id,
]);
} catch (\Exception $e) {
Log::channel('scheduled-errors')->error('Error processing task', [
'task_id' => $task->id,
@ -281,11 +298,8 @@ private function getBackupSkipReason(ScheduledDatabaseBackup $backup, ?Server $s
return null;
}
private function getTaskSkipReason(ScheduledTask $task, ?Server $server): ?string
private function getTaskCriticalSkipReason(ScheduledTask $task, ?Server $server): ?string
{
$service = $task->service;
$application = $task->application;
if (blank($server)) {
$task->delete();
@ -300,17 +314,22 @@ private function getTaskSkipReason(ScheduledTask $task, ?Server $server): ?strin
return 'subscription_unpaid';
}
if (! $service && ! $application) {
if (! $task->service && ! $task->application) {
$task->delete();
return 'resource_deleted';
}
if ($application && str($application->status)->contains('running') === false) {
return null;
}
private function getTaskRuntimeSkipReason(ScheduledTask $task): ?string
{
if ($task->application && str($task->application->status)->contains('running') === false) {
return 'application_not_running';
}
if ($service && str($service->status)->contains('running') === false) {
if ($task->service && str($task->service->status)->contains('running') === false) {
return 'service_not_running';
}

View file

@ -69,7 +69,11 @@ public function manualCheckStatus()
public function mount()
{
$this->parameters = get_route_parameters();
$this->parameters = [
'project_uuid' => $this->database->environment->project->uuid,
'environment_uuid' => $this->database->environment->uuid,
'database_uuid' => $this->database->uuid,
];
}
public function stop()