A Game decided during shutdown is lost #434

Closed
opened 2026-10-15 22:24:05 +00:00 by root · 1 comment
root commented 2026-10-15 22:24:05 +00:00 (Migrated from gitlab.core-project.space)

What happens

A Game decided while the API shuts down is dropped. GamesService.record starts its write without awaiting it and tracks it in inFlight (apps/api/src/games/games.service.ts:180-185). On shutdown nothing waits for inFlight, while DatabaseService.onApplicationShutdown closes the pool (apps/api/src/common/database.service.ts:28-30). The write fails and is only logged.

Every deploy restarts the API, so any Game that ends in that window is lost. Losing the live Room on restart is accepted (ADR 0015); losing a Game that was already decided is not.

Done when

  • GamesService waits on settled() in beforeApplicationShutdown, so pending writes finish before the pool closes.
  • A test decides a Game, closes the app without waiting, and finds the Game stored.
## What happens A Game decided while the API shuts down is dropped. `GamesService.record` starts its write without awaiting it and tracks it in `inFlight` (`apps/api/src/games/games.service.ts:180-185`). On shutdown nothing waits for `inFlight`, while `DatabaseService.onApplicationShutdown` closes the pool (`apps/api/src/common/database.service.ts:28-30`). The write fails and is only logged. Every deploy restarts the API, so any Game that ends in that window is lost. Losing the live Room on restart is accepted (ADR 0015); losing a Game that was already decided is not. ## Done when - `GamesService` waits on `settled()` in `beforeApplicationShutdown`, so pending writes finish before the pool closes. - A test decides a Game, closes the app without waiting, and finds the Game stored.
root commented 2026-10-15 22:38:37 +00:00 (Migrated from gitlab.core-project.space)

Investigated: does not reproduce on main. A test that decides a Game by resignation, then closes the app without awaiting settled() (write confirmed in flight), finds the Game stored. pg-pool's end() waits for checked-out clients, and store() checks its client out before anything is awaited, so the commit finishes before the pool closes. Nest's express adapter waits for in-flight requests, and no timer decides a Game.

A narrower gap, from reading code only: if the pool is saturated (pg default max 10) when a Game is decided during shutdown, store()'s connect is queued, and pg-pool neither serves nor rejects that queue once ending is set, so the write would hang silently. beforeApplicationShutdown() { await this.settled(); } on GamesService would close it, but only a contrived test (a 1-client pool) can show it.

Owner decision: close as not reproducible, or rescope to the pool-saturation case.

Investigated: does not reproduce on main. A test that decides a Game by resignation, then closes the app without awaiting `settled()` (write confirmed in flight), finds the Game stored. pg-pool's `end()` waits for checked-out clients, and `store()` checks its client out before anything is awaited, so the commit finishes before the pool closes. Nest's express adapter waits for in-flight requests, and no timer decides a Game. A narrower gap, from reading code only: if the pool is saturated (pg default max 10) when a Game is decided during shutdown, `store()`'s connect is queued, and pg-pool neither serves nor rejects that queue once `ending` is set, so the write would hang silently. `beforeApplicationShutdown() { await this.settled(); }` on `GamesService` would close it, but only a contrived test (a 1-client pool) can show it. Owner decision: close as not reproducible, or rescope to the pool-saturation case.
root (Migrated from gitlab.core-project.space) closed this issue 2026-10-16 06:34:36 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amaurycoudr/chess-project#434
No description provided.