otel/perf: JIT-warm the hot pages at boot to kill the cold-start p99 tail

The blog render path (comp-fold + relations + typed-block) JIT-compiles on first
call, so the first visitor after a restart paid ~2.5s (vs ~78ms warm) — that was
the /:slug p99 tail. Define the route groups once, render / + welcome +
nt-live-encore + /otel through a throwaway app at boot to force compilation, then
reset the otel ring so warmup spans don't skew live metrics.
This commit is contained in:
2026-07-01 19:24:09 +00:00
parent d357a5a7b9
commit 6868d984a0

View File

@@ -187,13 +187,22 @@ EPOCH=1
echo "(epoch $EPOCH)"
echo "(eval \"(host/static-build-sxh-index!)\")"
EPOCH=$((EPOCH+1))
# Route groups defined ONCE so warmup + serve use the exact same list. otel early
# so /otel isn't swallowed by /:slug; blog-routes LAST — its GET /:slug catch-all
# must not shadow the rest. The write routes (POST /new, POST/PUT/DELETE /posts)
# are guarded by host/require-user (session login OR Bearer) + ACL; make-app
# auto-mounts /login + /logout and wraps all of it in the signed-session middleware.
echo "(epoch $EPOCH)"
# Anonymous reads (feed timeline + relations container reads + blog post detail)
# plus the GUARDED blog write routes: POST /new (editor form ingest), POST/PUT/
# DELETE /posts behind host/require-user (session login OR Bearer) + ACL. make-app
# auto-mounts /login + /logout and wraps everything in the signed-session
# middleware, so a browser logs in then publishes. The bearer resolver is a stub
# (no API tokens configured) — browser session is the live auth path for now.
# blog-routes LAST — its GET /:slug catch-all must not shadow the rest.
echo "(eval \"(host/serve $PORT (list host/static-routes otel/routes host/feed-routes host/relations-routes (host/blog-write-routes (fn (tok) nil)) host/blog-routes))\")"
echo "(eval \"(define host/-serve-groups (list host/static-routes otel/routes host/feed-routes host/relations-routes (host/blog-write-routes (fn (tok) nil)) host/blog-routes))\")"
EPOCH=$((EPOCH+1))
# JIT warmup: render the hot pages once through a throwaway app so the FIRST real
# visitor after a restart doesn't eat the cold-compile cost. The blog render path
# (comp-fold + relations + typed-block) JIT-compiles on first call — that was the
# ~2.5s p99 on /:slug, vs ~78ms warm. Reset the otel ring after so warmup spans
# don't skew the live metrics.
echo "(epoch $EPOCH)"
echo "(eval \"(let ((warm (host/make-app host/-serve-groups))) (begin (warm (dream-request \\\"GET\\\" \\\"/\\\" {} \\\"\\\")) (warm (dream-request \\\"GET\\\" \\\"/welcome\\\" {} \\\"\\\")) (warm (dream-request \\\"GET\\\" \\\"/nt-live-encore\\\" {} \\\"\\\")) (warm (dream-request \\\"GET\\\" \\\"/otel\\\" {} \\\"\\\")) (otel/reset!) nil))\")"
EPOCH=$((EPOCH+1))
echo "(epoch $EPOCH)"
echo "(eval \"(host/serve $PORT host/-serve-groups)\")"
} | exec "$SX_SERVER"