Skip to content

Commit bd5328b

Browse files
Show activity-path alert details in Waterline coordination alerts
Format the workflow `activity_path` health check facts into a rich Waterline coordination alert detail string when the check warns. Mirrors the existing `task_transport` activity-path detail pattern: counts overdue activities (schedule-to-start, start-to-close, schedule-to-close, or heartbeat deadline past due without enforcement), worst-case overdue and retry ages, retry-backlog count, and the highest attempt count, then surfaces them in the alert details so operators can read the activity-path stuck/duplicate-risk state from one alert without re-aggregating metrics. The new check name is added by the workflow Composer package on `durable-workflow/workflow` v2. The Waterline change is purely additive: when the package version Waterline runs against does not yet emit `activity_path`, the new match arm is unreached and existing behaviour is unchanged. When it does emit `activity_path`, the existing `coordinationAlerts` infrastructure already routes the check into the Waterline UI, and this commit upgrades the alert from a default summary to the rich activity-path detail string.
1 parent 98b05fb commit bd5328b

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

app/Http/Controllers/V2HealthController.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ private function healthCheckAlertDetails(string $key, array $facts): ?string
162162
{
163163
return match ($key) {
164164
'task_transport' => $this->taskTransportAlertDetails($facts),
165+
'activity_path' => $this->activityPathAlertDetails($facts),
165166
'routing_health' => $this->routingHealthAlertDetails($facts),
166167
'durable_resume_paths' => $this->durableResumePathAlertDetails($facts),
167168
'worker_compatibility' => $this->workerCompatibilityAlertDetails($facts),
@@ -221,6 +222,56 @@ private function taskTransportAlertDetails(array $facts): ?string
221222
return $parts !== [] ? ucfirst(implode('; ', $parts)).'.' : null;
222223
}
223224

225+
/**
226+
* @param array<string, mixed> $facts
227+
*/
228+
private function activityPathAlertDetails(array $facts): ?string
229+
{
230+
$timeoutOverdue = $this->integerValue($facts['timeout_overdue'] ?? 0);
231+
$retrying = $this->integerValue($facts['retrying'] ?? 0);
232+
$maxTimeoutOverdueAgeMs = $this->integerValue($facts['max_timeout_overdue_age_ms'] ?? 0);
233+
$maxRetryingAgeMs = $this->integerValue($facts['max_retrying_age_ms'] ?? 0);
234+
$maxAttemptCount = $this->integerValue($facts['max_attempt_count'] ?? 0);
235+
236+
$parts = [];
237+
238+
if ($timeoutOverdue > 0) {
239+
$parts[] = sprintf(
240+
'%d activity execution%s past a schedule-to-start, start-to-close, schedule-to-close, or heartbeat deadline without enforcement',
241+
$timeoutOverdue,
242+
$timeoutOverdue === 1 ? '' : 's',
243+
);
244+
}
245+
246+
if ($maxTimeoutOverdueAgeMs > 0) {
247+
$parts[] = sprintf(
248+
'worst-case overdue age %s',
249+
$this->formatDurationMilliseconds($maxTimeoutOverdueAgeMs),
250+
);
251+
}
252+
253+
if ($retrying > 0) {
254+
$parts[] = sprintf(
255+
'%d activity execution%s in the retry backlog',
256+
$retrying,
257+
$retrying === 1 ? '' : 's',
258+
);
259+
}
260+
261+
if ($maxRetryingAgeMs > 0) {
262+
$parts[] = sprintf(
263+
'worst-case retry age %s',
264+
$this->formatDurationMilliseconds($maxRetryingAgeMs),
265+
);
266+
}
267+
268+
if ($maxAttemptCount > 0) {
269+
$parts[] = sprintf('highest attempt count %d', $maxAttemptCount);
270+
}
271+
272+
return $parts !== [] ? ucfirst(implode('; ', $parts)).'.' : null;
273+
}
274+
224275
/**
225276
* @param array<string, mixed> $facts
226277
*/

0 commit comments

Comments
 (0)