skip to content

An AWS Lambda function invoked asynchronously (InvocationType Event) throws on every attempt. Describe what Lambda does with that event from the moment it accepts it until the event is gone for good.

level: middleimportance: must knowfreq 66%

answer

  1. AWS holds the event, not the caller
  2. two bounds, whichever hits first
  3. attempts and age, configured together
  4. the default is two extra tries
  5. nothing catches it unless you asked

basics

~20 s

Lambda queues the event, returns 202, then invokes the function. On failure it retries twice by default with delays of minutes, subject to a maximum event age of six hours. After that the event is discarded unless a failure destination or dead-letter queue captures it.

solid answer

~50 s

When you invoke asynchronously, Lambda writes the payload into an AWS-managed internal queue and answers 202 straight away. It then reads the event and invokes the function. A handler error makes Lambda retry — by default twice more, with a delay of roughly a minute before the first retry and a couple of minutes before the second, so an event can bounce around for several minutes. Two settings bound this, both on the function's event-invoke config: `MaximumRetryAttempts` (0 to 2, default 2) and `MaximumEventAgeInSeconds` (60 to 21600, default six hours). Whichever fires first ends the event's life. If retries are exhausted or the event ages out, Lambda drops it — permanently and silently — unless you configured an on-failure destination or a `DeadLetterConfig` target to receive it. Throttling and internal errors are treated differently: Lambda keeps retrying those until the age limit.

code

bash · 4 lines
bash
aws lambda put-function-event-invoke-config \
  --function-name my-function \
  --maximum-retry-attempts 0 \
  --maximum-event-age-in-seconds 3600

go deeper

for a junior

Recall that Lambda retries a failed asynchronous invocation a small, fixed number of times and then gives up, and that the caller never hears about any of it.

for a middle

Name both bounds — MaximumRetryAttempts and MaximumEventAgeInSeconds — with their defaults, explain that retries are spaced minutes apart, and state clearly that an unconfigured failure path means the event is lost.

for a senior

Demonstrate that you would tune these rather than inherit them: short event ages for time-sensitive work, alarms on Errors and on delivery failures to the failure target, and an eye on AsyncEventAge for backlog.

for a principal

Frame the defaults as a policy decision with cost and correctness consequences — retry amplification during a dependency outage, the replay story for captured events, and who is accountable for draining a failure queue.

## What "accepted" actually means An asynchronous invoke does not start your function. Lambda validates the request, writes the payload into an internal queue that AWS operates on your behalf, and returns HTTP 202 with an empty body. The caller is done at that point and has no channel to learn anything more. Everything after this is Lambda's responsibility, which is exactly why you need to know the policy it applies. ## The retry loop Lambda reads the event from that queue and invokes the function. If the handler throws — or times out, which counts as a failure — Lambda retries the *same event*. As of 2025, the default is two retries beyond the first attempt, so three invocations in total, and the retries are spaced out rather than immediate: roughly one minute after the first failure and about two minutes after the second. This spacing is deliberate. Asynchronous failures are usually transient dependency problems, and an immediate retry would just hit the same broken dependency. Each attempt is a full, independent invocation: it gets its own execution environment (possibly a fresh one, possibly a warm reuse), its own entry in the `Errors` metric, and its own CloudWatch log output. That means a handler with a side effect that succeeded before the failure point will perform that side effect again. ## The two knobs Both live on the function's asynchronous invocation config, set with `PutFunctionEventInvokeConfig`: - `MaximumRetryAttempts` — an integer from 0 to 2, default 2. Setting it to 0 means one attempt and no retries. - `MaximumEventAgeInSeconds` — from 60 to 21600 (six hours), default six hours. This measures how long the event may live from the moment Lambda accepted it, including the queue wait. ```bash aws lambda put-function-event-invoke-config \ --function-name my-function \ --maximum-retry-attempts 0 \ --maximum-event-age-in-seconds 3600 ``` The two limits are independent, and whichever is reached first ends the event. That matters for a time-sensitive workload: an event that would be useless if delivered an hour late should carry a short maximum event age, so it is discarded rather than acted on stale. ## Errors versus throttles Lambda distinguishes a function that failed from a function it could not run. A handler error consumes a retry attempt. But when the invocation cannot be made at all — the account or function is out of available concurrency, or Lambda hits an internal service error — Lambda keeps retrying with backoff for as long as the maximum event age allows, without burning your retry attempts on it. This is the property that makes the asynchronous path a genuine buffer in front of a rate-limited function: a burst does not become a wall of dropped events, it becomes a queue that drains. The exception worth remembering is a function whose reserved concurrency is set to zero. There is no capacity by definition, so Lambda does not sit and retry indefinitely against it. ## Where the event goes when it dies This is the part candidates skip. If the retries are exhausted, or the event exceeds its maximum age, **Lambda discards it**. Nothing raises an alarm on its own, nothing writes the payload anywhere you can read it, and the original caller was never listening. Unless you configured an on-failure destination or the older `DeadLetterConfig` target, the business event is gone. So an asynchronously invoked function that carries real work needs three things wired up: 1. A failure destination (or dead-letter target) so the payload survives. 2. An alarm on the `Errors` metric, and on `DeadLetterErrors` or `DestinationDeliveryFailures` — because the mechanism that saves failed events can itself fail, usually because the execution role lacks permission to write to the target. 3. An eye on the asynchronous-path metrics Lambda publishes — `AsyncEventsReceived`, `AsyncEventAge` and `AsyncEventsDropped` — which are the only way to see a growing backlog or events dying of old age. ## Why the defaults bite The default of two retries plus minute-scale delays means a single poisoned event occupies a few minutes of intermittent capacity, and a *flood* of poisoned events triples your invocation volume and your bill. Conversely, two retries is far too few for a dependency that is down for twenty minutes. Neither default is wrong; both are worth setting deliberately rather than inheriting.

  • How does Lambda treat an asynchronous invocation that is throttled rather than one that errors?
    Throttles and Lambda's own internal errors do not consume the configured retry attempts. Lambda keeps re-attempting delivery with backoff until the maximum event age expires, which is what lets the asynchronous path absorb a burst against a concurrency-limited function. A handler error is different: each failure spends one of the two attempts.
  • You set MaximumRetryAttempts to 0. What have you actually changed, and what should you add?
    One attempt and no retries, so a single transient dependency blip now loses the event outright. That is a reasonable choice for a non-idempotent handler, but only if you pair it with an on-failure destination so the payload is captured and can be replayed deliberately after you fix the cause.
  • Which CloudWatch metrics tell you asynchronous events are backing up or being dropped?
    `AsyncEventsReceived` shows what Lambda accepted, `AsyncEventAge` shows how long events are sitting in the internal queue before invocation, and `AsyncEventsDropped` counts events discarded without being delivered. A rising AsyncEventAge is the early warning; AsyncEventsDropped is the damage report.

saying these in an interview costs you the question

  • Thinks a failed async event lands in CloudWatch Logs for replay
  • Says Lambda retries forever until the function succeeds
  • Confuses the async retry limit with an SQS visibility timeout
  • Believes retries are immediate rather than minutes apart
  • Assumes a dead-letter target exists by default

context