This is a large scale refactor to run all DB transaction code
asynchronsouly. At it's core, better-sqlite3 is a synchronous DB
library. Newer versions disallow transaction code that returns Promises
completely. As such, we've been stuck on older code (and this is
blocking other things, like NodeJS version bumps because of binary
interface changes).
Here we translate all kysely transaction code to Drizzle, because only
the latter supports synchronous execution of queries. This includes a
ton of DB migration code, since changing that completely to something
Drizzle-first is a much larger undertaking that will be tackled in a
follow-up.
This change should unblock the following:
1. Bumping better-sqlite3
2. Bumping nodejs version bumps
3. Paves the way towards Drizzle-only migrations
4. Will allow us to switch over from sync => async results using Drizzle
builders more easily in the future, should we decide to change the
underlying sqlite driver.
The segmentsToKeepBefore buffer could extend the playlist window below
#highestDeletedBelow, causing the playlist to reference segment files
that had already been deleted from disk. Clients requesting those
segments would get 404s.
Add a segmentFloor option to FilterBeforeSegmentNumber that acts as a
hard lower bound for minSeg, and pass #highestDeletedBelow as the floor
from HlsSession.trimPlaylist().
When endSession() stops a session, the run() loop exits asynchronously
and unconditionally called scheduleCleanup(), setting a 15-second timer.
If a new session was created for the same channel within that window, the
old timer's cleanup handler would delete the new session from the map —
causing 404s on subsequent playlist requests.
Three fixes applied:
- Cancel pending cleanup timers in Session.stop() so they never fire
after the session is explicitly stopped
- Skip scheduleCleanup() in HlsSession.run() when state is already
'stopped' (the stop path already handled cleanup)
- Guard 'cleanup' and 'stop' event handlers in SessionManager to verify
the session in the map is the same instance before deleting