SaveMyCert
Log in
5 of 5 free questions left today·for unlimited practice
Development with AWS Services

AWS Lambda for Developers: Configuration, Events, Concurrency and Tuning

16 min readDVA-C02 · Development with AWS ServicesUpdated

AWS Lambda runs your code in managed, ephemeral execution environments that scale automatically with incoming events — and writing code that behaves correctly inside that model is among the most heavily tested skills on the DVA-C02 exam. Lambda questions appear across every domain, but this task owns the developer fundamentals: how a function is configured, how it reaches private resources in a VPC, what happens when an invocation fails, and how concurrency and cold starts shape performance. The exam is precise here. It expects you to know that asynchronous invocations are retried twice while synchronous ones are never retried by Lambda, that memory is the dial that also controls CPU, and that an SQS-triggered function needs its queue's visibility timeout set with care. This lesson works through the execution model, function configuration, VPC networking, invocation semantics and error handling, event source mappings, concurrency, performance tuning, and near-real-time processing patterns.

What you’ll learn
  • Configure Lambda memory, timeout, environment variables, layers, extensions, triggers, and destinations for a given workload
  • Connect Lambda functions to VPC-private resources using ENIs, security groups, VPC endpoints, and RDS Proxy
  • Distinguish synchronous, asynchronous, and poll-based invocation and predict retry behavior for each
  • Handle failures with Lambda Destinations, dead-letter queues, and partial batch responses
  • Tune concurrency with reserved and provisioned concurrency and diagnose throttling
  • Reduce cold-start latency with initialization best practices, provisioned concurrency, and SnapStart

The Lambda execution model: handler, init phase, and environment reuse

Lambda executes your code inside an isolated execution environment that the service creates, reuses, and eventually retires — and understanding that lifecycle explains most Lambda behavior on the exam. When an event arrives and no idle environment exists, Lambda runs the init phase: it provisions the environment, downloads your code, starts the runtime and any extensions, and executes all code outside the handler — top-level imports, client construction, configuration loading. Only then does the invoke phase call your handler, the function you name in configuration as the entry point, passing the event and a context object. That first, full startup is a cold start; its latency is the init phase.

After the invocation, the environment is frozen, not destroyed. The next event may thaw and reuse it — a warm invocation that skips init entirely. Everything in global scope survives: SDK clients, database connections, cached configuration, and files written to /tmp. This is why the core Lambda coding practice is to initialize expensive resources outside the handler, so hundreds of warm invocations reuse one client and one connection instead of rebuilding them per event.

Reuse is an optimization, never a guarantee. Lambda may run your code in many environments in parallel and can recycle any of them at any time, so treat globals and /tmp (512 MB by default, configurable up to 10 GB) strictly as a cache. Correctness must never depend on state from a previous invocation — durable state belongs in a database, cache, or object store. Functions that honor this are stateless in the way the platform assumes, which is exactly what lets Lambda scale by simply creating more environments.

Configuring the function: memory, timeout, runtime, variables, layers, extensions

Function configuration is a compact set of parameters, and the exam tests the consequences of each. Memory is allocated from 128 MB up to 10,240 MB — and CPU scales proportionally with it, with roughly one full vCPU available at 1,769 MB. There is no separate CPU setting, so memory is the primary performance dial: a CPU-bound function is often made faster, and sometimes cheaper overall, by raising memory. Timeout can be set up to 900 seconds — 15 minutes — and that ceiling is a favorite exam fact: any workload that needs longer must be redesigned, for example by splitting the work into steps coordinated by Step Functions or moving to container-based compute. The runtime selects the language environment, and the handler setting names the file and function Lambda invokes.

Environment variables supply per-function configuration — endpoints, table names, feature flags — without code changes; all of a function's variables together are limited to 4 KB. They are encrypted at rest, but genuinely sensitive values belong in a secrets service and get fetched at init, a pattern the security domain covers in depth. Layers package shared libraries and dependencies separately from your function code; a function can attach up to five, keeping deployment packages lean and letting many functions share one dependency set. Extensions run alongside the runtime within the environment — monitoring agents, secrets caches — hooking the environment lifecycle.

Two more settings round out the model: triggers, the event sources permitted to invoke the function, and destinations, where Lambda sends invocation results — both covered with the event lifecycle below.

Accessing private resources in a VPC from Lambda code

Accessing VPC-private resources — an RDS database in a private subnet, an ElastiCache cluster, an internal service — requires attaching your function to the VPC, because by default Lambda runs in an AWS-managed network that has internet access but no route into your private subnets. You attach a function by specifying subnets and security groups in its VPC configuration. Lambda then creates elastic network interfaces (ENIs) in those subnets through its Hyperplane networking layer; the ENIs are created once per unique subnet and security-group combination and shared across execution environments, so scaling does not mint a new ENI per invocation.

Two consequences follow, and both are exam bait. First, security groups still rule: the database's security group must allow inbound traffic on the database port from the function's security group, or connections silently time out. Second, a VPC-attached function loses direct internet access. If it must call external APIs, its subnets need a route through a NAT gateway. If it only needs AWS services, prefer VPC endpoints: gateway endpoints for S3 and DynamoDB, and interface endpoints (AWS PrivateLink) for services like Secrets Manager, SQS, and KMS — keeping traffic private with no NAT at all.

The database-specific hazard is connection exhaustion. Each concurrent execution environment opens its own database connections, so a traffic spike can scale Lambda past what the database accepts. Amazon RDS Proxy is the exam's answer: it maintains a shared, pooled set of connections to RDS or Aurora, multiplexes function connections onto it, supports IAM authentication, and rides through failovers. When a scenario says Lambda is exhausting database connections, choose RDS Proxy.

Invocation types and the event lifecycle

Lambda has three invocation models, and predicting retry behavior for each is a guaranteed exam skill.

ModelExample sourcesRetry behaviorWhere errors go
SynchronousAPI Gateway, Application Load Balancer, direct RequestResponse invokeLambda performs no retries — the caller decidesError returned in the response to the caller
AsynchronousS3 event notifications, SNS, EventBridgeTwo automatic retries after the first failure, with waits between attemptsDead-letter queue or onFailure destination after retries are exhausted
Poll-based (event source mapping)SQS, Kinesis, DynamoDB StreamsGoverned by the source: stream batches retry until success, expiry, or configured limits; SQS messages reappear after the visibility timeoutBack to the queue (then its DLQ), or a stream on-failure destination

In a synchronous invocation the caller waits for the response and receives any error directly; if retries are wanted, the client or SDK must perform them. In an asynchronous invocation Lambda queues the event internally and immediately returns an accepted response; a separate process invokes the function, and on failure retries twice — three attempts total. You can tune this with the maximum retry attempts setting and a maximum event age, after which undelivered events are discarded or routed to your failure handling. In the poll-based model, Lambda itself polls the source on your behalf and invokes the function synchronously with batches of records — so retry semantics come from the event source mapping and the source's own redelivery rules, not from the async retry system. Misattributing async retry behavior to synchronous or poll-based invocations is the classic wrong answer.

Handling failures: Destinations, dead-letter queues, and partial batch responses

Failure handling in Lambda is configured, not just coded, and each invocation model has its own tools. For asynchronous invocations, once retries are exhausted the event can go to a dead-letter queue — an SQS queue or SNS topic that receives the event payload — or, better, to an onFailure destination. Lambda Destinations accept SQS, SNS, EventBridge, or another Lambda function as targets and send a record containing the request payload plus the response context and error details, which a DLQ does not include; AWS recommends Destinations over DLQs for async error handling. The matching onSuccess destination forwards successful results, letting you chain functions without writing invocation code.

Stream sources (Kinesis and DynamoDB Streams) add a twist: records in a shard are ordered, so by default a failing batch is retried until it succeeds or the data expires, blocking that shard behind the failure. The event source mapping gives you controls — maximum retry attempts, maximum record age, bisect batch on function error (split the batch to isolate the bad record), and an on-failure destination that receives metadata describing the skipped records so processing can move on.

For SQS and stream batches alike, enable partial batch responses: with ReportBatchItemFailures turned on, your handler returns a batchItemFailures list naming only the records that failed, and only those are retried instead of the whole batch. Walk the scenario: a payment processor reads batches of ten SQS messages and one is malformed. Without partial batch responses, all ten return to the queue and nine successful payments are reprocessed — duplicate side effects unless the handler is idempotent. With partial batch responses, only the poison message retries, and after exceeding the queue's maxReceiveCount it lands in the queue's dead-letter queue for inspection.

Event source mappings: batch size, batching windows, and scaling behavior

An event source mapping is the Lambda-managed poller that reads from SQS, Kinesis, or DynamoDB Streams and invokes your function with batches — the machinery behind the poll-based model. Its two headline settings trade latency against efficiency. Batch size caps how many records one invocation receives. The batching window (MaximumBatchingWindowInSeconds) tells the poller how long to wait to fill a batch before invoking anyway: a longer window means fewer, fuller, cheaper invocations; a zero window means minimum latency. Event source mappings can also apply event filtering, discarding non-matching records before any invocation happens — often the cheapest optimization available, since filtered records never invoke the function at all.

For SQS sources, Lambda scales its pollers up as the backlog grows and back down as it drains. The critical interaction is with the queue's visibility timeout: a batch in flight must stay invisible for as long as processing might take, so AWS recommends setting the visibility timeout to at least six times the function timeout. Set it too low and in-flight messages reappear and process twice.

For Kinesis and DynamoDB Streams, the mapping processes each shard with one concurrent invocation by default, preserving order within the shard, so total concurrency tracks shard count. The parallelization factor raises this to as many as ten concurrent batches per shard, still keeping records with the same partition key in order. The starting position chooses whether a new mapping reads only new records or begins from the oldest available data. When a scenario says stream processing is falling behind, the levers are parallelization factor, batch size, function duration — or more shards.

Concurrency: reserved, provisioned, burst, and throttling

Concurrency is the number of invocations a function is serving at the same instant — each in its own execution environment — and it is the unit in which Lambda scales and throttles. All functions in a Region share one concurrency pool (the default quota is 1,000, raisable by support request). When demand would exceed available concurrency, invocations are throttled, and what that means depends on the invocation model: synchronous callers receive a 429 throttling error and must retry; asynchronous events are returned to Lambda's internal queue and retried automatically for up to several hours; poll-based sources simply back off and retry the batch. Scaling is fast but not unbounded — each function can add up to 1,000 concurrent executions every 10 seconds — so an extreme spike can throttle briefly even below quota.

DimensionReserved concurrencyProvisioned concurrency
What it doesDedicates part of the pool to one function — a guarantee and a hard capKeeps a set number of environments initialized and warm
Cold startsNot affectedEliminated for the provisioned capacity
CostFreeBilled while configured, whether or not invoked
Use whenProtecting a downstream database, guaranteeing capacity, or capping spend — set it to zero to disable a function entirelyLatency-critical synchronous paths that cannot tolerate cold starts

Keep the two straight: reserved concurrency is about how much a function may scale — it both guarantees that capacity and prevents the function from exceeding it. Provisioned concurrency is about how fast requests are served — pre-warmed environments answer without init latency. A function can use both together.

Performance tuning, testing, and near-real-time processing

Performance tuning starts with the memory dial: because CPU scales with memory, benchmarking the same function at several memory sizes often finds a setting that is faster and cheaper, since billing is duration times memory and duration falls. The next wins are in the init phase — create SDK clients and database connections outside the handler, reuse HTTP connections with keep-alive, lazily load rarely used dependencies, and keep the deployment package small so it downloads and initializes quickly. For cold starts that still hurt, two platform features apply. Provisioned concurrency keeps environments warm for any runtime, billed while configured. SnapStart instead snapshots the fully initialized environment and resumes new environments from that snapshot — built for runtimes with expensive startup, first for Java and since extended to Python and .NET. With SnapStart, remember that anything computed during init is captured in the snapshot, so uniqueness — random seeds, temporary credentials — must be re-derived after restore.

Testing Lambda code spans three layers. Unit tests exercise your business logic with the handler treated as thin wiring and SDK clients mocked. The console's test events invoke the deployed function with saved JSON payloads. Locally, sam local generate-event produces realistic event JSON for sources like S3 or SQS, sam local invoke runs the function in a Lambda-like container against that payload, and sam local start-lambda exposes a local endpoint your integration tests can call through the SDK.

Finally, near-real-time processing is Lambda consuming a stream via an event source mapping — transforming, enriching, or filtering records within seconds of arrival and forwarding results downstream. Keep batches and timeouts small for latency, use partial batch responses, and remember the managed variant: Amazon Data Firehose can invoke a Lambda function to transform records in flight before delivery.

Tip. The exam probes Lambda through precise behavioral questions: which invocation types retry (async twice, sync never, poll-based per the source), what a VPC-attached function can and cannot reach, and which concurrency control fixes a given symptom — reserved for protecting a downstream database or capping scale, provisioned for cold-start latency. Scenario stems about duplicate processing, a blocked shard, or messages reappearing mid-processing point at partial batch responses, bisect-on-error, and the visibility-timeout rule. Watch for trigger words like cold start, connection exhaustion, throttling, in order, and near real time — each maps to a specific feature, and distractors typically apply the right fix to the wrong invocation model.

Key takeaways
  • CPU scales with memory — memory is the primary performance dial, with roughly one vCPU at 1,769 MB
  • Maximum timeout is 900 seconds (15 minutes); longer workloads need Step Functions or different compute, not a bigger timeout
  • Asynchronous invocations are retried twice (three attempts total); synchronous invocations are never retried by Lambda — the caller must retry
  • Prefer an onFailure Destination over a DLQ for async errors: it carries the error and response context, and supports SQS, SNS, EventBridge, or Lambda targets
  • For SQS event sources, set the queue's visibility timeout to at least six times the function timeout and enable ReportBatchItemFailures so only failed records retry
  • Reserved concurrency guarantees and caps capacity for free; provisioned concurrency pre-warms environments for a price — reserved is how much, provisioned is how fast
  • A VPC-attached function loses internet access without a NAT gateway; use VPC endpoints for AWS services and RDS Proxy when Lambda exhausts database connections
  • Initialize SDK clients and connections outside the handler — warm environments reuse them, and it is the cheapest cold-start optimization available

Frequently asked questions

Does AWS Lambda retry failed invocations?

It depends entirely on the invocation type. Synchronous invocations (API Gateway, direct RequestResponse calls) are never retried by Lambda — the error goes back to the caller, which must retry itself. Asynchronous invocations (S3, SNS, EventBridge) are retried twice after the initial failure, with waits between attempts, before the event goes to a dead-letter queue or onFailure destination if configured. Poll-based sources follow their own rules: failed SQS batches reappear after the visibility timeout, and stream batches are retried per the event source mapping's retry and age limits.

How do I connect a Lambda function to a database in a private VPC?

Attach the function to the VPC by specifying subnets and security groups in its configuration; Lambda creates shared elastic network interfaces in those subnets so your code can reach private resources. The database's security group must allow inbound traffic on its port from the function's security group. Note that a VPC-attached function loses internet access unless its subnets route through a NAT gateway, and for relational databases at scale you should put RDS Proxy in front so pooled connections absorb Lambda's concurrency instead of exhausting the database.

What is the difference between reserved and provisioned concurrency in Lambda?

Reserved concurrency dedicates a slice of your account's regional concurrency pool to one function — it guarantees that capacity, hard-caps the function at it, costs nothing, and set to zero it disables the function. Provisioned concurrency keeps a chosen number of execution environments fully initialized so requests are served with no cold start; it is billed for as long as it is configured. Reserved answers how much a function may scale; provisioned answers how fast requests are served. They can be used together.

How do I reduce Lambda cold starts?

First shrink the init phase: keep the deployment package small, initialize SDK clients and connections outside the handler, and load heavy dependencies lazily. Then, if latency targets still demand it, use provisioned concurrency to keep environments pre-warmed for synchronous, latency-critical paths, or SnapStart, which resumes new environments from a snapshot of the initialized state and suits runtimes with expensive startup such as Java. Raising memory also helps, because more CPU makes initialization itself run faster.

What is a Lambda event source mapping?

An event source mapping is a Lambda-managed poller that reads from a source such as SQS, Kinesis, or DynamoDB Streams and invokes your function synchronously with batches of records — you configure it rather than writing polling code. Its key settings are batch size, the batching window (how long to wait to fill a batch), event filtering to discard records before invocation, and error-handling controls like partial batch responses, bisect-on-error, maximum retry attempts, and an on-failure destination for stream sources.

What are the maximum timeout and memory for a Lambda function?

The maximum timeout is 900 seconds — 15 minutes — and the timeout you configure applies per invocation. Memory ranges from 128 MB to 10,240 MB, and CPU is allocated in proportion to memory, with roughly one full vCPU at 1,769 MB. If a workload cannot finish within 15 minutes, the answer is architectural: break it into smaller steps orchestrated by Step Functions or run it on a container service, never a larger timeout.

Test yourself on this topic
Practice questions with full explanations.
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.