Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
580a4b7f60 fix(presence): heartbeat self-heals when worker record disappears
Previously, if the ClaudeWorker record vanished (deleted by
prisma_workers_cleanup, manual cleanup, or a race during shutdown of a
parallel worker), the heartbeat would log a warning and stop itself
permanently. From that moment the NavBar showed 'Geen agent' for the
rest of the MCP-server process lifetime — even though the agent was
still alive and serving tools.

Fix: on result.count === 0, call registerWorker again so the record is
re-created. Heartbeat keeps ticking. Self-healing instead of self-
terminating.

startHeartbeat now also accepts userId (needed for re-registration);
caller in index.ts updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 20:16:30 +02:00
2 changed files with 13 additions and 4 deletions

View file

@ -68,7 +68,7 @@ async function main() {
// is up, regardless of when the MCP client sends its first request.
const auth = await getAuth()
await registerWorker({ userId: auth.userId, tokenId: auth.tokenId })
const { stop: stopHeartbeat } = startHeartbeat({ tokenId: auth.tokenId })
const { stop: stopHeartbeat } = startHeartbeat({ userId: auth.userId, tokenId: auth.tokenId })
registerShutdownHandlers({ userId: auth.userId, tokenId: auth.tokenId, stopHeartbeat })
const transport = new StdioServerTransport()

View file

@ -1,6 +1,8 @@
import { prisma } from '../prisma.js'
import { registerWorker } from './worker.js'
export function startHeartbeat(opts: {
userId: string
tokenId: string
intervalMs?: number
}): { stop: () => void } {
@ -11,11 +13,18 @@ export function startHeartbeat(opts: {
data: { last_seen_at: new Date() },
})
if (result.count === 0) {
console.error('[scrum4me-mcp] Heartbeat: worker record not found — token may be revoked. Stopping.')
clearInterval(timer)
// Record disappeared — likely deleted by prisma_workers_cleanup,
// a manual cleanup, or a race during shutdown of a parallel worker.
// Re-register so the UI's 'Agent verbonden'-indicator self-heals
// instead of going dark for the rest of the process lifetime.
try {
await registerWorker({ userId: opts.userId, tokenId: opts.tokenId })
} catch (err) {
console.error('[scrum4me-mcp] Heartbeat: re-register failed', err)
}
}
} catch {
// non-fatal
// non-fatal — next tick retries
}
}, opts.intervalMs ?? 5_000)