fix(agent): await child completion in /agent/v1/exec route
Fastify-handler returnde direct na het attachen van event handlers.
Fastify finaliseerde dan de reply waardoor `req.raw.on('close')` direct
firede en `child.kill()` aanriep voordat het kind iets kon produceren.
Symptoom: SSE bevatte alleen `event:exit code:null` zonder stdout/stderr,
audit-log toonde `exit_code:null duration_ms:0`, dashboard-modules
toonden "No containers running" / "No data" terwijl handmatige command
prima werkte.
Wrap de event-handlers in een Promise zodat de async route-handler wacht
op child close/error voordat ie returnt. Verplaats client-disconnect
detectie van `req.raw.on('close')` naar `reply.raw.on('close')` — die
fired bij echte connectie-sluiting, niet bij request body parse.
Bevestigd: `docker_ps` retourneert nu volledige container-lijst, dashboard
/docker pagina rendert alle 6 containers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f7821c05be
commit
6581a9ef33
1 changed files with 28 additions and 15 deletions
|
|
@ -108,20 +108,33 @@ export async function execRoutes(app: FastifyInstance): Promise<void> {
|
|||
sendEvent('stderr', chunk.toString());
|
||||
});
|
||||
|
||||
// Houd de route-handler open totdat het kind klaar is. Zonder dit return-t
|
||||
// de async functie meteen, finaliseert Fastify de reply, en triggert dat
|
||||
// `req.raw.on('close')` → `child.kill()` voordat het kind iets kon doen.
|
||||
await new Promise<void>((resolve) => {
|
||||
let settled = false
|
||||
const finish = () => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
resolve()
|
||||
}
|
||||
child.on('close', (code) => {
|
||||
auditLog(command_key, args, code, Date.now() - startedAt);
|
||||
reply.raw.write(`event: exit\ndata: ${JSON.stringify({ code })}\n\n`);
|
||||
reply.raw.end();
|
||||
});
|
||||
|
||||
auditLog(command_key, args, code, Date.now() - startedAt)
|
||||
reply.raw.write(`event: exit\ndata: ${JSON.stringify({ code })}\n\n`)
|
||||
reply.raw.end()
|
||||
finish()
|
||||
})
|
||||
child.on('error', (err) => {
|
||||
auditLog(command_key, args, null, Date.now() - startedAt);
|
||||
reply.raw.write(`event: error\ndata: ${JSON.stringify({ message: err.message })}\n\n`);
|
||||
reply.raw.end();
|
||||
});
|
||||
|
||||
req.raw.on('close', () => {
|
||||
child.kill();
|
||||
});
|
||||
auditLog(command_key, args, null, Date.now() - startedAt)
|
||||
reply.raw.write(`event: error\ndata: ${JSON.stringify({ message: err.message })}\n\n`)
|
||||
reply.raw.end()
|
||||
finish()
|
||||
})
|
||||
// Detect client disconnect via response stream (niet request stream —
|
||||
// die fired al direct na request body parse).
|
||||
reply.raw.on('close', () => {
|
||||
if (!settled) child.kill()
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue