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
A newly created Netlify function instance stalls its event loop for roughly 24 seconds on its first invocation, before any application work. This is the whole of the ~30 s tail on public routes, and it is what made the Prisma connect budget look broken in #1120 — a setTimeout cannot fire on a blocked loop, so pg's 3 s connect timer reported at ~26 s.
Measured on deploy preview 1123 with a temporary diagnostic route that ran 400 ms of pure idle await, touching no database at all, while sampling event-loop lag every 50 ms. Forty invocations across two 20-way concurrent rounds:
instance age
process.uptime()
invocation
400 ms idle phase took
max loop lag
first DB attempt
40 ms
3,363 ms
1
23,905 ms
23,746 ms
ok in 862 ms
39 ms
3,361 ms
1
24,634 ms
24,534 ms
ok in 866 ms
100 ms
3,355 ms
1
24,823 ms
24,655 ms
ok in 1,037 ms
The remaining 37, every one of them on an instance at least 47 s old, completed the same idle phase in 400–453 ms with 1–70 ms of lag. So the stall is bimodal, it is confined to brand-new instances serving invocation 1, and the database is fast on both sides of it.
Why it matters
It is the only remaining cause of 30-second page loads on the public routes, and it scales with instance creation, which means it fires exactly when traffic arrives in a burst. It cannot be mitigated from application code: #1123 established that no timeout value can bound it, and shipped the only two things that help — retrying past it, and serving from the ISR cache so the function is not invoked at all.
What is not yet known
The cause of the stall is not identified. The obvious candidate is cold-instance JavaScript evaluation and GC at Lambda's memory-proportional CPU share, but that is inference. The facts in hand:
AWS_LAMBDA_FUNCTION_MEMORY_SIZE is 1024, so the function gets roughly 0.58 vCPU.
V8 reports a heap limit of 1,018 MB, and RSS at rest is 675–795 MB. The instance is running close to its container.
process.env.NODE_OPTIONS is null inside the function, so netlify.toml's --max-old-space-size=6144 is not leaking into the runtime and letting V8 overrun the container. That hypothesis is ruled out.
Worth trying, in rough order of expected value
Raise the function's memory, which raises its CPU with it. Netlify does not expose this on the current plan, so this is a conversation with Netlify rather than a config change, but it is the most direct lever if the stall is CPU-bound.
Confirm the cause before optimising anything. A CPU profile of a cold invocation would settle it, and the diagnostic-route technique in fix: stop caching degraded renders, and correct the root cause of the 30s tail #1123 is the way to get data out — the function log strips our console.* and does not expose instance identity, so the response body is the only reliable channel.
Follow-up to #1120. Related: #1117 (PG_POOL_MAX=1), #1122 (console.* is stripped in production).
What was measured
A newly created Netlify function instance stalls its event loop for roughly 24 seconds on its first invocation, before any application work. This is the whole of the ~30 s tail on public routes, and it is what made the Prisma connect budget look broken in #1120 — a
setTimeoutcannot fire on a blocked loop, so pg's 3 s connect timer reported at ~26 s.Measured on deploy preview 1123 with a temporary diagnostic route that ran 400 ms of pure idle
await, touching no database at all, while sampling event-loop lag every 50 ms. Forty invocations across two 20-way concurrent rounds:process.uptime()The remaining 37, every one of them on an instance at least 47 s old, completed the same idle phase in 400–453 ms with 1–70 ms of lag. So the stall is bimodal, it is confined to brand-new instances serving invocation 1, and the database is fast on both sides of it.
Why it matters
It is the only remaining cause of 30-second page loads on the public routes, and it scales with instance creation, which means it fires exactly when traffic arrives in a burst. It cannot be mitigated from application code: #1123 established that no timeout value can bound it, and shipped the only two things that help — retrying past it, and serving from the ISR cache so the function is not invoked at all.
What is not yet known
The cause of the stall is not identified. The obvious candidate is cold-instance JavaScript evaluation and GC at Lambda's memory-proportional CPU share, but that is inference. The facts in hand:
AWS_LAMBDA_FUNCTION_MEMORY_SIZEis1024, so the function gets roughly 0.58 vCPU.process.env.NODE_OPTIONSisnullinside the function, sonetlify.toml's--max-old-space-size=6144is not leaking into the runtime and letting V8 overrun the container. That hypothesis is ruled out.Worth trying, in rough order of expected value
optimizePackageImports; a bundle analysis of the server handler specifically would say whether there is more to take out.console.*and does not expose instance identity, so the response body is the only reliable channel.Follow-up to #1120. Related: #1117 (
PG_POOL_MAX=1), #1122 (console.*is stripped in production).