refactor(jobs): split task skip checks into critical and runtime phases
Some checks failed
Staging Build / build-push (aarch64, linux/aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Staging Build / build-push (amd64, linux/amd64, ubuntu-24.04) (push) Has been cancelled
Staging Build / merge-manifest (push) Has been cancelled

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 @@ class ScheduledJobManager implements ShouldQueue
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 @@ class ScheduledJobManager implements ShouldQueue
$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 @@ class ScheduledJobManager implements ShouldQueue
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 @@ class ScheduledJobManager implements ShouldQueue
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 @@ class Heading extends Component
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()