Skip to content

Commit 8aabd3e

Browse files
operator-dashboard: fix missing model reference and DB-portable trends
OperatorDashboardSummary referenced a nonexistent model class (WorkflowWorkerCompatibilityHeartbeat) and queried columns (last_heartbeat_at) that don't exist on the heartbeats table, so any dashboardSummary() call from Waterline crashed before producing output. Also replace the MySQL-only DATE_FORMAT() in fleetTrendsSeries with PHP-side hourly bucketing so the query runs under SQLite, PostgreSQL, SQL Server, and MySQL alike. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6e8b98c commit 8aabd3e

1 file changed

Lines changed: 12 additions & 16 deletions

File tree

src/V2/Support/OperatorDashboardSummary.php

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use Workflow\V2\Enums\RunStatus;
1010
use Workflow\V2\Models\WorkflowFailure;
1111
use Workflow\V2\Models\WorkflowRunSummary;
12-
use Workflow\V2\Models\WorkflowWorkerCompatibilityHeartbeat;
12+
use Workflow\V2\Models\WorkerCompatibilityHeartbeat;
1313

1414
final class OperatorDashboardSummary
1515
{
@@ -49,19 +49,14 @@ public static function fleetTrendsSeries(?CarbonInterface $now = null): array
4949
$now ??= now();
5050
$weekAgo = $now->copy()->subWeek();
5151

52-
// Get all terminal runs (completed, failed, cancelled, terminated) in last 7 days
53-
// Group by hour
54-
$runs = self::summaryModel()::query()
55-
->select(
56-
DB::raw('DATE_FORMAT(closed_at, "%Y-%m-%d %H:00:00") as hour'),
57-
'status_bucket',
58-
DB::raw('COUNT(*) as count')
59-
)
52+
// Fetch terminal-run rows in the last 7 days and bucket them hourly in PHP
53+
// to avoid DB-specific date formatting (DATE_FORMAT is MySQL-only).
54+
$rows = self::summaryModel()::query()
55+
->select('closed_at', 'status_bucket')
6056
->whereNotNull('closed_at')
6157
->where('closed_at', '>=', $weekAgo)
6258
->whereIn('status_bucket', ['completed', 'failed'])
63-
->groupBy('hour', 'status_bucket')
64-
->orderBy('hour')
59+
->orderBy('closed_at')
6560
->get();
6661

6762
// Build time series with all hours (fill gaps with zeros)
@@ -72,8 +67,9 @@ public static function fleetTrendsSeries(?CarbonInterface $now = null): array
7267
];
7368

7469
$hourCounts = [];
75-
foreach ($runs as $run) {
76-
$hourCounts[$run->hour][$run->status_bucket] = $run->count;
70+
foreach ($rows as $row) {
71+
$hourKey = $row->closed_at->copy()->startOfHour()->format('Y-m-d H:00:00');
72+
$hourCounts[$hourKey][$row->status_bucket] = ($hourCounts[$hourKey][$row->status_bucket] ?? 0) + 1;
7773
}
7874

7975
// Generate all hours in the range
@@ -246,9 +242,9 @@ private static function needsAttention(CarbonInterface $now): array
246242

247243
// 1. Stuck workers (no heartbeat in last 5 minutes)
248244
$staleHeartbeatThreshold = $now->copy()->subMinutes(5);
249-
$stuckWorkers = WorkflowWorkerCompatibilityHeartbeat::query()
250-
->where('last_heartbeat_at', '<', $staleHeartbeatThreshold)
251-
->where('last_heartbeat_at', '>', $now->copy()->subHour()) // Still recently active
245+
$stuckWorkers = WorkerCompatibilityHeartbeat::query()
246+
->where('recorded_at', '<', $staleHeartbeatThreshold)
247+
->where('recorded_at', '>', $now->copy()->subHour()) // Still recently active
252248
->count();
253249

254250
if ($stuckWorkers > 0) {

0 commit comments

Comments
 (0)