Skip to content

feat(vps): swap entry point to Effect toWebHandler (Step 2b)#145

Open
guidefari wants to merge 1 commit into
migration/2a-toweb-handler-fallbackfrom
migration/2b-swap-entry-point
Open

feat(vps): swap entry point to Effect toWebHandler (Step 2b)#145
guidefari wants to merge 1 commit into
migration/2a-toweb-handler-fallbackfrom
migration/2b-swap-entry-point

Conversation

@guidefari

@guidefari guidefari commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Why this exists: this is the actual cutover -- prod now serves through the Effect handler instead of Hono's Bun.serve directly. Route behavior is unchanged (still 100% Hono fallback under the hood), so this PR isolates one risk only: did the swap itself break anything (startup, shutdown, background jobs).

Stacked on #144 (merge #142 -> #143 -> #144 first).

Verification

  • Full apps/vps suite: 140/140 passing, unchanged from before this PR.
  • Background forks (reminders, sitemap) untouched -- still start the same way.
  • Shutdown: had to fix a real ordering bug here (see below), not just wire it up.

Not verified

No real SIGTERM against a booted server -- this environment can't boot vps standalone (needs SST resources). Worth a manual check on staging before prod.

The bug this caught

Naively adding a second process.on('SIGTERM', ...) for the new handler would race the existing one, which calls process.exit() unconditionally. Fixed by threading the new dispose call through the existing shutdown sequence instead.

Next

Step 2c: port the better-auth route onto the new router, isolated so an auth regression is diagnosable to one small diff.

Step 2b of the Hono -> Effect HttpApi migration
(docs/migration-effect-http-api.md). Serving topology change, zero
route behavior change -- still 100% Hono fallback.

- apps/vps/src/index.ts: Bun.serve's fetch now points at
  effectWebHandler.handler instead of app.fetch directly. Every
  request still reaches the same Hono app via the step 2a fallback.
- apps/vps/src/app.ts: added onShutdown(dispose) so the entry point
  can register effectWebHandler.dispose() to run before
  disposeRuntime() during SIGTERM/SIGINT. Sequenced inside the
  existing shutdown() closure (not a second process.on listener) so
  it can't race the existing process.exit(0)/exit(1) calls.

Background forks (reminder loop, sitemap regeneration) are
unaffected -- they run inside app.ts's initializeApp(), which the
entry point still imports and awaits before building the handler.

Verified: full apps/vps vitest suite (140/140, 15 files) passes
unchanged, including the step 1b/2a blackbox suites exercising the
new effectWebHandler end to end (health, a real API route, 404,
dispose() after serving real requests).

Not verified here: an actual OS-level SIGTERM against a running
Bun.serve process -- no local env/SST resources available in this
environment to boot the server standalone. The shutdown sequencing
was reasoned through manually (see comments) but a real signal to a
staged/dev instance is worth a manual check before this reaches
prod, per the doc's Step 2 acceptance bar.
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