Skip to content

fix(codegen): in-memory (Dynamic) handler codegen in Production#104

Merged
windischb merged 1 commit into
developfrom
fix/wolverine-codegen-static-prod
Jun 28, 2026
Merged

fix(codegen): in-memory (Dynamic) handler codegen in Production#104
windischb merged 1 commit into
developfrom
fix/wolverine-codegen-static-prod

Conversation

@windischb

@windischb windischb commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Problem

The deployed container logged this on the first hit of every handler:

Unable to write code file for GetAllUsersQueryHandler475384214
System.UnauthorizedAccessException: Access to the path '/app/Internal' is denied.

Wolverine ran codegen with TypeLoadMode.Auto. At runtime it generated each handler dynamically (Roslyn) and then tried to persist the source to /app/Internal — which the non-root app user cannot write (only /app/data is chowned). The write is non-fatal but noisy, and Auto's persisted source is never recompiled into the running image, so it buys nothing in a container.

Fix

Switch Production to TypeLoadMode.Dynamic: handlers are compiled in memory and never written to disk, so the error and the failed write disappear. Dev and the Testing-env integration suite keep Auto (writable working tree) and are unchanged.

One line, IsProduction()-gated. No Dockerfile or test-harness changes.

Road not taken — pre-gen + Static

The first attempt on this branch pre-generated the handler code in the Docker build and ran TypeLoadMode.Static to also eliminate the per-handler cold-compile. That requires JasperFx's RunJasperFxCommands entry point — and any reference to that API in this assembly wires JasperFx into the host resolution that WebApplicationFactory drives via HostFactoryResolver, which tore the integration-test host down before it initialized (Server hasn't been initialized yet). The official JasperFxEnvironment.AutoStartHost = true workaround in turn starts hosted services before the imperative multi-tenant bootstrap has provisioned the system tenant (UnknownTenantIdException: 'system').

So Static is deferred until the startup bootstrap can be reworked into ordered hosted services. Dynamic fixes the actual reported problem now; the only thing it doesn't recover is the cold-compile on the first hit after a restart (which the container pays today anyway).

Verification

  • ✅ Full backend suite green — 1254 unit + 444 integration tests pass.
  • ✅ The three integration classes the earlier Static attempt broke (FlavorRegistryTests, FirstSignalConsistencyFlowTests, AuthHardeningWave2Tests) pass.

🤖 Generated with Claude Code

The published container ran Wolverine codegen with TypeLoadMode.Auto. On the
first hit of every handler it generated the code dynamically (Roslyn) and then
tried to persist the source to /app/Internal — which the non-root `app` user
cannot write — logging "Access to the path '/app/Internal' is denied". The write
is non-fatal but noisy, and Auto's persisted source is never recompiled into the
running image, so it bought nothing in a container.

Switch Production to TypeLoadMode.Dynamic: handlers are compiled in memory and
never written to disk, so the error and the failed write are gone. Dev and the
Testing-env integration suite keep Auto (writable working tree), so they are
unchanged.

Note on the road not taken: pre-generating at build time + TypeLoadMode.Static
would also remove the per-handler cold-compile, but it requires JasperFx's
`RunJasperFxCommands` entry point. Any reference to that API in this assembly
wires JasperFx into the host resolution that WebApplicationFactory drives, which
tears the integration-test host down before it initializes ("Server hasn't been
initialized yet"); the official `JasperFxEnvironment.AutoStartHost` workaround in
turn starts hosted services before the imperative multi-tenant bootstrap has
provisioned the `system` tenant. Static is therefore deferred until the startup
bootstrap can be reworked into ordered hosted services.

Verified: full backend suite green — 1254 unit + 444 integration tests pass
(the integration classes that this approach's earlier Static attempt broke —
FlavorRegistryTests, FirstSignalConsistencyFlowTests, AuthHardeningWave2Tests —
included).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@windischb windischb force-pushed the fix/wolverine-codegen-static-prod branch from 3af10cf to b7ad11b Compare June 28, 2026 08:37
@windischb windischb changed the title fix(codegen): pre-generate Wolverine handlers + Static load in Production fix(codegen): in-memory (Dynamic) handler codegen in Production Jun 28, 2026
@windischb windischb merged commit 322ca21 into develop Jun 28, 2026
8 checks passed
@windischb windischb deleted the fix/wolverine-codegen-static-prod branch June 28, 2026 08:52
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