Skip to content

3.17.2 — Storage facade expansion: DB-only publishers

Choose a tag to compare

@opsnlops opsnlops released this 31 May 23:00

Patch release. Closes the second half of issue #11, addressing April's comment on the original ticket: "There's other places in the codebase where we need a facade. This includes creatures, fixtures, etc."

3.17.1 shipped the file-storage half (JobWorker handlers + DialogCache + read-side path resolution). This release ships the DB-only half — every paired DB-write/cache-invalidation in controllers and services now goes through the creatures::storage facade. The original footgun ("forgot to fire scheduleCacheInvalidationEvent after a DB write") is structurally impossible now.

New facade surface

11 new functions in creatures::storage, all pairing a DB call with the matching invalidation atomically:

Function DB call + invalidation(s)
publishCreature upsertCreature + Creature
publishFixture upsertFixture + Fixture
deleteFixture deleteFixture + Fixture
setFixtureUniverse setFixtureUniverse + Fixture
publishPlaylist upsertPlaylist + Playlist
publishDialogScript upsertDialogScript + DialogScriptList
deleteDialogScript deleteDialogScript + DialogScriptList
publishStoryboard upsertStoryboard + StoryboardList
deleteStoryboard deleteStoryboard + StoryboardList
deleteAnimation deleteAnimation + Animation
broadcastCacheInvalidation(type) named manual broadcast for the few remaining spots where the mutation happens outside our process (Debug refresh buttons + the legacy Voice sound-write that still goes through CreatureVoicesLib plumbing)

Shared runPublisher<DbCall, Caches...> template owns the "call DB, fire invalidations only on success" contract — used by every publisher including the three from 3.17.1 (refactored).

Migrations

  • DialogScript + Storyboard controllers (×3 each): direct publishX / deleteX
  • DmxFixture / Creature / Animation / Playlist services: db->upsertX/deleteX → storage::publishX/deleteX; their controllers then drop the now-redundant scheduleCacheInvalidationEvent lines
  • Voice + Debug controllers: broadcastCacheInvalidation
  • AnimationController delete keeps its belt-and-suspenders synchronous broadcastCacheInvalidationToAllClients for the irreversible op

Audit (the regression proof)

grep -rn 'scheduleCacheInvalidationEvent' src/server/ws/{controller,service}/   → empty
grep -rn 'db->upsert|db->delete|db->insert' src/server/ws/{controller,service}/ → empty

Tests

19 new PublishersTest.* pin the pairing contract per function — success-path verifies the exact CacheTypes fire, failure-path verifies nothing fires (invalidations are atomic with the DB call). FakeDatabase gains a testing::setFakeDatabaseSucceeds(bool) toggle for happy-path tests; FakeWebsocketUtils keeps a thread-local invalidation log so tests can assert without standing up a real EventLoop. Full suite 158 / 158 (was 139 + 19 new).

Verification

Live smoke against deployed 3.17.2:

  • Storyboard create + delete → both clients refresh
  • DialogScript create + delete → both clients refresh
  • Debug refresh button → clients refresh
  • Wire envelope unchanged (lowercase "ok" / "error" / "not_found" from issue #16 intact)

Notes