diff --git a/services/mam-api/src/scheduler.js b/services/mam-api/src/scheduler.js index d77726c..3865bb4 100644 --- a/services/mam-api/src/scheduler.js +++ b/services/mam-api/src/scheduler.js @@ -137,10 +137,11 @@ async function tick() { // Orphaned live assets: recorder stopped but asset still 'live'. // Happens when the capture sidecar crashes before finalize() runs. - // Wait 90s grace before marking error — this prevents a mam-api restart - // from racing the capture container's finalize() POST, which can take up - // to 30s for large files on a slow upload or busy node. - const ORPHAN_GRACE_SECONDS = parseInt(process.env.ORPHAN_GRACE_SECONDS || '90', 10); + // Grace window is measured from when the RECORDER was last updated + // (i.e. when it transitioned to stopped), not from asset creation. + // This prevents a race where the scheduler fires before the capture + // container's finalize POST lands (can take 30-60s on large files). + const ORPHAN_GRACE_SECONDS = parseInt(process.env.ORPHAN_GRACE_SECONDS || '120', 10); const orphanResult = await client.query( `UPDATE assets a SET status = 'error', updated_at = NOW() @@ -148,7 +149,7 @@ async function tick() { WHERE a.status = 'live' AND a.display_name = r.current_session_id AND r.status = 'stopped' - AND a.updated_at < NOW() - ($1 || ' seconds')::INTERVAL + AND r.updated_at < NOW() - ($1 || ' seconds')::INTERVAL RETURNING a.id, a.display_name`, [ORPHAN_GRACE_SECONDS] );