You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(runtime): per-request kernel lives on the request, not on the dispatcher (#5155)
One HttpDispatcher serves a whole host, but the kernel a request resolves to
is per request. That answer was stored on the instance field `this.kernel`,
written once per request by `resolveRequestScope()` and read by every service
lookup afterwards — each behind at least one `await`. Two interleaved requests
on a multi-tenant host therefore swapped data sources under each other: A
resolved env-1, yielded, B resolved env-2, and A resumed reading env-2.
`HttpProtocolContext` now carries `kernel`, written by `resolveRequestScope()`
next to the `environmentId` / `dataDriver` / `executionContext` it already
writes there. `this.kernel` is gone. Every kernel-reading member of
`DomainHandlerDeps` / `ActionExecutionDeps` takes the request as its first
parameter, so the dependency is visible at the call site and the compiler asks
for it — chosen over AsyncLocalStorage, which would have reintroduced implicit
mutable ambient context, the same defect in a new costume.
Three host-level readers (`/ready`, its driver-health probe, the memoized
`default-project` lookup) now name `defaultKernel` explicitly instead of
reading whichever tenant resolved most recently.
Covered by a deterministic interleaving regression test: request A parks inside
its own identity resolution, request B runs to completion, A resumes. On the
old code A is served env-2's i18n bundle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VkPSGsX9o17MsGv3Lbxu2w
fix(runtime): the HTTP dispatcher serves each request from its OWN resolved kernel — two tenants can no longer swap data sources under each other (#5155)
6
+
7
+
A host constructs exactly **one**`HttpDispatcher` (`dispatcher-plugin.ts`
8
+
`start()`), and every route it serves shares that instance. The kernel a request
9
+
resolves to, however, is per request: on a multi-tenant host the injected
10
+
`kernelResolver` (ADR-0006) picks a different one per environment.
11
+
12
+
That per-request answer was being stored on a dispatcher **instance field**,
13
+
`this.kernel`, written once per request by `resolveRequestScope()` and then read
14
+
by `resolveService()` / `getService()` / `getObjectQL()` /
0 commit comments