record($event->task, TaskRunStatus::Success, null, (int) round($event->runtime * 1000)); } public function onFailed(ScheduledTaskFailed $event): void { $this->record($event->task, TaskRunStatus::Failed, $event->exception->getMessage(), null); } private function record(ScheduledEvent $task, TaskRunStatus $status, ?string $message, ?int $durationMs): void { // $task->command is the full shelled-out string (php binary, // artisan path, output redirection) — pull out just the artisan // signature. Anything that isn't one of our own commands (there // are none today, but a future package could schedule its own) is // simply not tracked here. if (! preg_match('/projectsend:[\w-]+/', (string) $task->command, $matches)) { return; } ScheduledTaskRun::query()->updateOrCreate( ['command' => $matches[0]], ['status' => $status, 'message' => $message, 'duration_ms' => $durationMs, 'ran_at' => now()], ); } }