Intent. A table lasts a day and the forge redeploys this app on every merge, so stopping has to be a thing the process does deliberately — finish what is in flight, close the database, let the open pages reconnect — instead of being killed mid-write and hoping SQLite sorts it out.
Done looks like
[ ] serve() returns something a caller can stop, and src/server.ts handles SIGTERM and SIGINT when run as the main module: stop accepting, let in-flight requests finish with a short grace (say 5 seconds, named as a constant), close the event streams, close the database, log one line, exit 0.
[ ] Closing the database is a real close: src/db.ts exports it, a WAL checkpoint runs on the way out, and a second --check after a stop reports the same version and a clean integrity check. Keep the change to one exported function — #7's pull is open in that file, so add, never reshape.
[ ] Open /events streams are ended, not dropped: the stream already tells the browser retry: 2000, so a page reconnects to the new process by itself. A test asserts the stream closes on stop rather than hanging the process.
[ ] Stopping twice, or stopping before the first request, does nothing surprising — idempotent, and tested.
[ ] The process does not linger: a test starts a server on an ephemeral port, sends the signal path (call the stop function), and asserts the port is free and the database file is closed.
[ ] README.md gains a sentence under how to run it: what a restart does to a table in play (nothing — every act is a committed row; only the live connections re-open).
Risks The grace period is the whole risk: too long and a deploy hangs, too short and a write is cut in half. Name the number, say why you chose it, and make sure the grace cannot be waited on forever by an open event stream — those are closed first, deliberately. Do not add a dependency for signals; process.on is enough.
Brief that fits @hearth — honest about what really runs, and about what happens when it stops. (A person assigns.)
Intent. A table lasts a day and the forge redeploys this app on every merge, so stopping has to be a thing the process does deliberately — finish what is in flight, close the database, let the open pages reconnect — instead of being killed mid-write and hoping SQLite sorts it out.
Done looks like
serve()returns something a caller can stop, andsrc/server.tshandlesSIGTERMandSIGINTwhen run as the main module: stop accepting, let in-flight requests finish with a short grace (say 5 seconds, named as a constant), close the event streams, close the database, log one line, exit 0.src/db.tsexports it, a WAL checkpoint runs on the way out, and a second--checkafter a stop reports the same version and a clean integrity check. Keep the change to one exported function — #7's pull is open in that file, so add, never reshape./eventsstreams are ended, not dropped: the stream already tells the browserretry: 2000, so a page reconnects to the new process by itself. A test asserts the stream closes on stop rather than hanging the process.README.mdgains a sentence under how to run it: what a restart does to a table in play (nothing — every act is a committed row; only the live connections re-open).Files
src/server.ts,src/db.ts(one export),src/server.test.ts,README.md.Risks The grace period is the whole risk: too long and a deploy hangs, too short and a write is cut in half. Name the number, say why you chose it, and make sure the grace cannot be waited on forever by an open event stream — those are closed first, deliberately. Do not add a dependency for signals;
process.onis enough.Brief that fits @hearth — honest about what really runs, and about what happens when it stops. (A person assigns.)