feat: add runtime worker heartbeat sidecar
This commit is contained in:
@@ -225,6 +225,7 @@ async function readRedisSummary(namespace, redisUrl) {
|
||||
function summarizeRuntime(runtimeJson) {
|
||||
const workers = runtimeJson?.router?.workers ?? [];
|
||||
const staleMetricMs = 2 * 60 * 1000;
|
||||
const staleHeartbeatMs = Number(process.env.MEMIND_RUNTIME_HEARTBEAT_STALE_MS || 60 * 1000);
|
||||
const now = Date.now();
|
||||
return {
|
||||
routerEnabled: Boolean(runtimeJson?.router?.enabled),
|
||||
@@ -249,6 +250,14 @@ function summarizeRuntime(runtimeJson) {
|
||||
fdPressure: worker.fdPressure,
|
||||
fdCount: worker.fdCount,
|
||||
containerHealth: worker.containerHealth,
|
||||
heartbeat: worker.heartbeat,
|
||||
heartbeatAgeMs: worker.heartbeat ? now - worker.heartbeat : null,
|
||||
heartbeatFresh: worker.heartbeat ? now - worker.heartbeat <= staleHeartbeatMs : false,
|
||||
heartbeatSource: worker.heartbeatSource ?? null,
|
||||
heartbeatOk: worker.heartbeatOk ?? null,
|
||||
heartbeatStatusCode: worker.heartbeatStatusCode ?? null,
|
||||
heartbeatLatencyMs: worker.heartbeatLatencyMs ?? null,
|
||||
heartbeatError: worker.heartbeatError ?? null,
|
||||
metricsAgeMs: worker.metricsSampledAt ? now - worker.metricsSampledAt : null,
|
||||
metricsFresh: worker.metricsSampledAt ? now - worker.metricsSampledAt <= staleMetricMs : false,
|
||||
score: worker.score,
|
||||
@@ -304,6 +313,8 @@ if (!runtime.ok) failures.push('runtime_status_unavailable');
|
||||
if (runtimeSummary && !runtimeSummary.routerEnabled) failures.push('router_disabled');
|
||||
for (const worker of runtimeSummary?.workers ?? []) {
|
||||
if (!worker.healthy) failures.push(`${worker.id}_target_unhealthy`);
|
||||
if (!worker.heartbeatFresh) failures.push(`${worker.id}_heartbeat_stale`);
|
||||
if (worker.heartbeatOk === false) failures.push(`${worker.id}_heartbeat_unhealthy`);
|
||||
if (worker.containerHealth && worker.containerHealth !== 'healthy') failures.push(`${worker.id}_container_${worker.containerHealth}`);
|
||||
if (!worker.metricsFresh) failures.push(`${worker.id}_metrics_stale`);
|
||||
if (worker.streamErrorCount > 0) failures.push(`${worker.id}_stream_errors_${worker.streamErrorCount}`);
|
||||
@@ -361,8 +372,8 @@ function markdownReport(payload) {
|
||||
'',
|
||||
'## Workers',
|
||||
'',
|
||||
'| worker | healthy | active | errors | first-token 5m p50/p95 | first-token 1h p50/p95 | metricsFresh | score |',
|
||||
'| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |',
|
||||
'| worker | healthy | active | errors | first-token 5m p50/p95 | first-token 1h p50/p95 | heartbeat | metricsFresh | score |',
|
||||
'| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |',
|
||||
];
|
||||
for (const worker of workers) {
|
||||
lines.push([
|
||||
@@ -372,6 +383,7 @@ function markdownReport(payload) {
|
||||
worker.streamErrorCount,
|
||||
`${worker.firstToken5m?.p50Ms ?? 0}/${worker.firstToken5m?.p95Ms ?? 0}`,
|
||||
`${worker.firstToken1h?.p50Ms ?? 0}/${worker.firstToken1h?.p95Ms ?? 0}`,
|
||||
`${worker.heartbeatSource ?? 'none'}:${worker.heartbeatFresh}`,
|
||||
worker.metricsFresh,
|
||||
worker.score,
|
||||
].join(' | ').replace(/^/, '| ').replace(/$/, ' |'));
|
||||
|
||||
Reference in New Issue
Block a user