Skip to content

Slow first requests: cold starts

2 min read · main part only; folded sections are optional

After this you can answer: How do you prove a slow Lambda invocation was a cold start, and what would you change?

Troubleshooting scenario: the first worker invocation after idle takes longer; its Lambda REPORT includes “Init Duration:”. Later invocations are faster. A cold start initializes a new execution environment; it can also happen during scale-out, not just after idle.

Lambda reports initialization, not an error or IAM refusal. Under Reach / Allowed / Password, timing alone proves none of them failed. A dependency can also be slow on a warm run; an AccessDenied still needs missing-allow/explicit-deny analysis. MiniTickets’ API/web run on ECS, so a slow /events page is not automatically a Lambda cold start.

flowchart TB
A["Slow first invocation"] --> B{"Initialization visible?"}
B -->|"yes"| C["Compare init with total delay"]
B -->|"no"| D["Inspect dependency calls and queue age"]
C --> E{"Warm runs fast?"}
E -->|"yes"| F["Measure startup changes against latency needs"]
E -->|"no"| D

Ranked for first-only slowness with an initialization field.

  1. Runtime and application initialization in a new environment.
  2. Lazy first-use work, such as the tickets worker fetching its signing secret.
  3. Queue wait or downstream latency coincides with startup. These also affect warm runs and require separate timing evidence.

In /minitickets/dev/worker or /minitickets/dev/tickets, compare REPORT initialization and duration fields for several invocation ids. Compare Lambda Duration and SQS oldest-message age. Separate enqueue-to-start delay from work inside the handler.

Preserve SDK clients outside the handler, as current code does. Measure startup/dependency changes and memory settings with representative batches. These asynchronous workers tolerate queue delay; provisioned concurrency, paid preinitialized capacity, is a future option only if measured latency needs justify it. Reserved concurrency does not preinitialize environments.

Record separate cold/warm measurements after worker changes; watch end-to-end ticket/email delay. Do not promise a warm environment survives idle or that every first request has identical latency.

apps/worker/src/lambda.ts → handler; Inspect the tickets worker →.

Advanced: Historical measurement and logging limits

The local runtime-emulator run recorded in docs/40-aws-job-pipeline.md on 2026-10-15 had INIT 302 ms and a warm batch of 23 ms. These are local historical measurements, not current AWS latency promises, and the two numbers measure different phases. Neither function currently configures provisioned concurrency. Both use the worker image; email has 256 MB, tickets 512 MB. The signing-secret helper caches only successful reads in a warm process. AWS’s execution lifecycle also explains initialization after failures: a reset can cause a suppressed initialization inside the next reported duration. Absence of an obvious init field is not universal proof of a warm run. apps/worker/src/tickets/assets.ts → signingSecret; infra/src/tickets/lambda.ts → createTicketLambda.

Read this book online: https://book.theversehub.in/