|
1 | 1 | import { SnapshotOrphanSweeper } from "@internal/run-store"; |
2 | 2 | import { env } from "~/env.server"; |
3 | 3 | import { logger } from "~/services/logger.server"; |
| 4 | +import { signalsEmitter } from "~/services/signals.server"; |
4 | 5 | import { engine } from "./runEngine.server"; |
5 | 6 | import { runStoreWithoutSnapshotDecorator } from "./runStore.server"; |
6 | 7 | import { buildSnapshotSweepRunner } from "./snapshotSweepRunner.server"; |
7 | 8 | import { setSnapshotRepairEnqueuer, setSnapshotSweepRunner } from "./snapshotStoreBindings.server"; |
8 | | -import { getSnapshotSweepClient, registerSnapshotStoreQuit } from "./snapshotStoreInstance.server"; |
| 9 | +import { |
| 10 | + getSnapshotSweepClient, |
| 11 | + quitSnapshotStoreClients, |
| 12 | + registerSnapshotStoreQuit, |
| 13 | +} from "./snapshotStoreInstance.server"; |
9 | 14 |
|
10 | 15 | /** |
11 | 16 | * The third module: it imports both sides, so neither the run store nor the engine has to import |
@@ -43,6 +48,16 @@ export function registerSnapshotStoreWiring(): boolean { |
43 | 48 |
|
44 | 49 | registerSnapshotStoreQuit(() => sweeper.quit()); |
45 | 50 |
|
| 51 | + // Close the sweeper and all three connections on the way out, the same way the other Redis-backed |
| 52 | + // singletons do. `quitSnapshotStoreClients` is async and the signals emitter swallows listener |
| 53 | + // rejections, so discard the promise explicitly rather than handing it a floating one. The caller |
| 54 | + // wraps this function in `singleton`, so the listeners are registered once per process. |
| 55 | + const onShutdown = (): void => { |
| 56 | + void quitSnapshotStoreClients(); |
| 57 | + }; |
| 58 | + signalsEmitter.on("SIGTERM", onShutdown); |
| 59 | + signalsEmitter.on("SIGINT", onShutdown); |
| 60 | + |
46 | 61 | logger.info("snapshot store wiring registered"); |
47 | 62 | return true; |
48 | 63 | } |
0 commit comments