Add Bun + SQLite example app and pre-launch friction fixes by cgenuity · Pull Request #4 · delaykit/delaykit · GitHub
Skip to content

Add Bun + SQLite example app and pre-launch friction fixes#4

Merged
cgenuity merged 3 commits into
mainfrom
bun-example
Apr 29, 2026
Merged

Add Bun + SQLite example app and pre-launch friction fixes#4
cgenuity merged 3 commits into
mainfrom
bun-example

Conversation

@cgenuity

@cgenuity cgenuity commented Apr 29, 2026

Copy link
Copy Markdown
Member

Summary

  • New examples/bun-sqlite-server/ — a minimal single-file Bun server demonstrating dk.schedule, dk.getActiveJobByKey, and dk.unschedule against SQLiteStore + PollingScheduler. ~80 lines, inline DTO projection, one-call shutdown via dk.stop({ closeStore: true }). Run with bun run setup && bun run server.ts from a fresh clone.
  • BREAKING (pre-1.0): dk.getJobByKey renamed to dk.getActiveJobByKey for parity with the Store contract method. Behavior unchanged — terminal jobs still return null because the key may have been reused. New JSDoc clarifies the active-only filter and points to getJob(id) for status-agnostic lookup.
  • New StopOptions.closeStore?: boolean (default false) — dk.stop({ closeStore: true }) closes the store after the scheduler drains, hiding the lifecycle order inside the library. Default stays false to preserve the post-stop-cleanup contract (cancel/unschedule after stop) and the shared-pool case.
  • SQLiteStore.close() is now idempotent. JSDoc added to dk.stop() (states it is idempotent) and PollingScheduler constructor (summarizes default options).
  • docs/deploy.md canonical SIGTERM snippet updated to use closeStore: true and the new idempotent shutdown; pointer to the example added at the end of the Bun-server section.

Test plan

  • npm run typecheck — clean
  • npm run test — 469 passed
  • npm run test:postgres — 117 passed (Docker postgres up at `localhost:5444`)
  • npm run test:packaging — 8 passed
  • npm run test:bun — 199 passed
  • From a true fresh clone (delete `dist/` and `examples/bun-sqlite-server/{node_modules,bun.lock}`): `cd examples/bun-sqlite-server && bun run setup && bun run server.ts` boots cleanly
  • POST `/reminders` returns slim DTO with `created: true`; GET returns same shape; DELETE returns `{cancelled: true}`; GET after fire/cancel returns 404
  • SIGTERM and SIGINT each trigger clean shutdown ("Shutting down..." then exit)
  • Schedule a reminder, kill the server, restart it — reminder still pending and fires at its scheduled time (durability)

- Public method name now matches the Store contract method
  (store.getActiveJobByKey). Behavior unchanged: terminal jobs
  return null because the key may have been reused by a fresh
  schedule. The active-only filter is load-bearing for schedule
  idempotency, unschedule, debounce/throttle window semantics,
  and the assertKeyReusable invariant.
- JSDoc on the renamed method documents the filter and points to
  getJob(id) for status-agnostic lookup.
- JSDoc on the PollingScheduler constructor surfaces option
  defaults (interval 1000ms, stalledCheckInterval 30000ms,
  maxConcurrent 10) so new PollingScheduler() is self-documenting
  on hover.
- Pre-1.0 breaking; CHANGELOG entry under [Unreleased].
- dk.stop({ closeStore: true }) closes the store after the scheduler
  drains, hiding the scheduler.stop() → store.close() order inside
  the library where the invariant lives. The canonical shutdown for
  a long-running app that owns its store is now one call instead of
  two.
- Default closeStore: false preserves the post-stop-cleanup contract
  (cancel/unschedule remain available after dk.stop returns) and the
  shared-store / shared-pool case.
- dk.stop() docstring now states it is idempotent — repeated or
  concurrent calls await the same in-flight shutdown promise.
- SQLiteStore.close() is now idempotent (was throwing on second
  call). MemoryStore and PostgresStore were already idempotent.
- examples/bun-sqlite-server/ — minimal HTTP server demonstrating
  dk.schedule, getActiveJobByKey, and unschedule against a
  SQLiteStore + PollingScheduler. ~80 lines of server.ts with
  inline DTO projection and one-call shutdown via
  dk.stop({ closeStore: true }).
- README covers run, curl examples, env vars, and persistence
  across restarts. `bun run setup` builds the parent's dist/ and
  installs deps so a fresh clone runs cleanly with no extra steps.
- docs/deploy.md: canonical SIGTERM snippet updated to use
  closeStore: true and idempotent shutdown; pointer to the example
  added at the end of the Bun-server section.
@cgenuity cgenuity merged commit 40680aa into main Apr 29, 2026
6 checks passed
@cgenuity cgenuity deleted the bun-example branch April 29, 2026 20:34
cgenuity added a commit that referenced this pull request May 3, 2026
- Add Vocabulary preamble; renumber the remaining 7 invariants (former #3
  Identity model becomes the preamble; #4–#8 shift down)
- Remove the handler-idempotency invariant — it was end-user authoring
  guidance, not a property the library maintains, and is already covered by
  invariant #3 (atomic claim) and the README's Crash recovery paragraph
- Move schedule()/debounce()/throttle()/cancel() behavior spec to docs/api.md
  under a new Behavior section, with a back-pointer for the correctness model
- Replace the schema DDL with a one-line link to the migration files; keep
  the required-indexes paragraph (which is invariant material)
- Consolidate "Race conditions and recovery" from six implementation
  walkthroughs to four invariant-led subsections
- Drop the contract-test prescription from #2's "Active-slot acquisition"
  paragraph — test guidance, not a runtime contract
- Standardize "Posthook" capitalization (was "PostHook" in 4 spots)
- Update the one cross-reference (`invariant #4` → `invariant #3`) in both
  the doc and test/race-conditions.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant