Skip to content

perf(boot): drop two dead Node processes from container start - #236

Merged
Bccorb merged 1 commit into
mainfrom
perf/boot-startup
Aug 31, 2026
Merged

perf(boot): drop two dead Node processes from container start#236
Bccorb merged 1 commit into
mainfrom
perf/boot-startup

Conversation

@Bccorb

@Bccorb Bccorb commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Two of the three items in #205. The third is deliberately left alone, see below.

initKeys was doing nothing, in both modes

The issue treated this as a small 0.29s win worth folding into server startup. It is better than that: the step does no useful work at all.

  • In production the Dockerfile sets ENV NODE_ENV=production, and ensureKeys() is if (!isProduction) { ... } followed by a comment placeholder. The image was paying a full Node cold start to call an empty function. Production keys come from SEAMLESS_JWKS_KEY_*_PRIVATE, which validateEnvs.sh already requires.
  • In development it writes ./keys/private.pem and ./keys/public.pem, and nothing reads either. signingKeyStore.ts keeps its own keys at ./keys/dev/ and generates them lazily with an exclusive write, and jwks.ts serves ./keys/dev/public.pem. Two different directories.

So this is removed rather than folded into startup, which would only have moved dead code into the hot path.

exec node rather than npm run start

start is node dist/server.js, so npm was a second Node program loaded to run one command. It also sits between the init process and the server for the life of the container, so SIGTERM during ECS draining reaches npm rather than the server at PID 1.

Not done: moving migrations out of the entrypoint

This is the large item, 3.07s of the measured 6.78s, and it is the one I have left in place. Removing run_migrations here without a one-off migration task in seamless-iac running first would let a task boot against an un-migrated schema, which is worse than a slow boot and is the property the current design is protecting. It also does not fix the desiredCount: 2 race on its own. That needs a coordinated change in the IaC repo and should land there first.

#205 should stay open for that item.

Measurements

Local numbers, on a much faster machine than the 0.5 vCPU task in the issue, so these confirm the mechanism rather than the production magnitudes:

  • node dist/scripts/initKeys.js at NODE_ENV=production: 0.03s for a no-op (0.29s on the task)
  • the same trivial command through npm run vs directly: 0.07s vs 0.00s (0.37s on the task)

Against the issue's production log those two are about 0.66s of 6.78s. Re-measure on the task before touching seamless-iac#99, as the issue asks.

Verification

sh -n and shellcheck clean on validateEnvs.sh. Full gate green via the pre-commit hook: lint, format, typecheck, 1194 tests, coverage, build. No source change, so no changeset.

Two of the three items in #205. The third, moving migrations out of the
entrypoint, needs a one-off task in seamless-iac and is not safe to do here
alone, so it is left in place.

initKeys was doing nothing. The Dockerfile sets NODE_ENV=production and
ensureKeys() returns immediately on that branch, so the image was paying a
full Node cold start for an empty function. Even in development it writes
./keys/private.pem and ./keys/public.pem, which nothing reads: signingKeyStore
keeps its own keys under ./keys/dev and generates them lazily, and that is what
the JWKS route serves.

exec node instead of `npm run start` drops a second Node program whose only job
was to run one command, and puts the server at PID 1 so SIGTERM on task
draining reaches it rather than npm.
@Bccorb
Bccorb merged commit 32d7f66 into main Aug 31, 2026
5 checks passed
@Bccorb
Bccorb deleted the perf/boot-startup branch August 31, 2026 14:06
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