Chapter 1
Development with AWS Services
Picture this: it is 8:04 on a Friday night, and Daniel, the lead developer at a food-delivery startup, is watching his phone in horror. His team just launched a promotion — free delivery during the championship game — and orders are spiking forty times above normal. The fleet of EC2 instances running the order service is melting. Auto Scaling is adding servers, but each one takes four minutes to boot, configure, and join the load balancer. By the time a server is ready, the queue is already longer. Customers see spinning wheels. The on-call engineer is restarting instances by hand. Daniel does the math on the servers they will have paid for all month just to survive ninety minutes of fame, and he feels sick. Six weeks later, the same promotion runs again. This time there are no servers to boot. When an order comes in, AWS Lambda runs a function — in milliseconds, thousands of them in parallel, each handling exactly one order. API Gateway takes the HTTP requests from the app. DynamoDB stores the orders with single-digit-millisecond reads. When the spike ends, the meter stops. The bill for the ninety minutes is less than the cost of the pizza the team ordered to celebrate. That is what this chapter is about: building applications the way AWS intends developers to build them — with managed services that scale themselves, and with your code focused on business logic instead of infrastructure. The DVA-C02 exam devotes 32% of its questions to this domain, the largest single slice. It tests whether you know which service fits which job, how the services behave under load, and the sharp edges (timeouts, permissions, consistency) that bite developers who only read the marketing page.
AWS Lambda: Code Without Servers
AWS Lambda lets you run code without provisioning or managing servers. You upload your code, tell Lambda what should trigger it, and it runs — scaling from zero to thousands of parallel executions automatically. You pay per request and per millisecond of compute. When nobody calls your function, you pay nothing. A Lambda function has three essential parts: the code (your handler), the configuration (memory, timeout, environment variables, and the execution role), and the trigger (the event source). Understanding how these three interact is the foundation of half this domain.
A minimal Lambda handler in Python looks like this — the event dict is whatever the trigger sent, and the return value is the response:
import json
def lambda_handler(event, context):
name = event.get("name", "world")
return {
"statusCode": 200,
"body": json.dumps(f"Hello, {name}!")
}
Event Sources: Push vs. Pull
Lambda is event-driven : something happens, and your function runs in response. But not all triggers work the same way, and the exam loves this distinction. In the push model , the AWS service invokes your function directly. S3 event notifications, SNS topics, API Gateway, EventBridge rules, and Cognito all push: when an object is uploaded or a message published, the service calls Lambda's Invoke API with the event. Your function receives the event, does its work, and returns. In the pull model (also called event source mappings ), Lambda does the polling for you. Kinesis data streams, DynamoDB streams, SQS queues, and MSK topics work this way: Lambda continuously polls the source and invokes your function with batches of records. Two exam-critical consequences follow. First, the polling is at-least-once : the same record can be delivered twice, so your function logic must be idempotent — processing a record twice must cause no harm. Second, for stream sources (Kinesis, DynamoDB streams), ordering is guaranteed per shard (per partition key), and a poison record — one your function keeps failing on — blocks that shard until it succeeds or expires. The event source mapping's failure handling covers this: after a set number of retries, the failed batch goes to an on-failure destination (an SQS queue or SNS topic you configure); bisect-on-error splits a failing batch in half on each retry to isolate the poison record; and maximum record age discards records too stale to matter instead of letting them block the shard forever.
If a question describes duplicate record delivery from Kinesis or DynamoDB Streams, the answer is idempotency — never "increase batch size" or "enable provisioned concurrency." And if a failing record blocks a shard, think on-failure destination plus bisect-on-error — not bigger memory, and not the async-invocation DLQ (stream mappings use their own failure settings).
Execution Roles: Who Your Function Is
Every Lambda function runs with an execution role — an IAM role that grants the function permission to call other AWS services. When your function writes logs, it needs permission for CloudWatch Logs. When it reads from DynamoDB, it needs dynamodb:GetItem on that table. The exam draws a hard line here: the execution role is what the function uses to act outward on AWS resources. Do not confuse it with the function resource policy (also called the function policy), which controls who or what can invoke the function inward — for example, allowing S3 or SNS to call it. Execution role = what the function can do. Resource policy = who can call the function. A classic exam trap describes a function that cannot be triggered by S3 and asks about the execution role — the real problem is the missing resource-policy permission. One more rule that never changes: never put long-term credentials in code or environment variables. If a function needs AWS access, it uses the execution role, which provides temporary credentials automatically. Secrets (database passwords, API keys) belong in Secrets Manager or Parameter Store , fetched at runtime.
"Function cannot reach DynamoDB" check the execution role. "S3 cannot trigger the function" check the resource policy. The exam will swap these to test whether you know the direction of each permission.
Layers, Versions, and Aliases
Lambda layers let you package libraries, custom runtimes, or shared code separately from your function code. Five functions that all need the same image-processing library can share one layer instead of each bundling it. Layers are versioned, and a function references a specific layer version. Versions are immutable snapshots of your function code plus configuration. Publish version 3, and version 3 can never change — you always know exactly what ran. Aliases are named pointers to versions: the prod alias might point to version 3 today and version 4 tomorrow. Aliases enable weighted routing : send 90% of traffic to the stable version and 10% to the new one — a canary deployment with no extra infrastructure. The exam's favorite trap here is confusing the two: versions are immutable snapshots; aliases are movable pointers.
Concurrency, Timeouts, and Memory
Concurrency is how many function instances run at the same time. By default, functions share your account's regional concurrency quota (1,000). Two settings change this. Reserved concurrency guarantees a function a slice of that quota — and caps it there, which also acts as a throttle protecting downstream resources (like a database with limited connections). Provisioned concurrency goes further: it keeps a set number of instances initialized and ready , eliminating cold starts for latency-sensitive workloads. You pay for provisioned concurrency whether it is used or not. A cold start is the delay when Lambda must initialize a new execution environment (download code, start runtime). It matters most for heavier runtimes such as Java and .NET. SnapStart takes a snapshot of the initialized environment and restores it instead of running initialization each time — dramatically cutting cold starts. SnapStart supports Java 11+, Python 3.12+, and .NET 8+ . Timeout is configurable from 1 second to 15 minutes . If your function runs longer, Lambda kills it. Memory is configurable too, and it proportionally scales CPU — more memory means more CPU and faster execution, which sometimes lowers the bill because the function finishes sooner. But memory does not fix everything: a function waiting on a slow downstream API needs a longer timeout, not more memory.
Cold start fixes in exam-land: provisioned concurrency (pay to keep warm), SnapStart (snapshot restore for Java, Python, .NET). Reserved concurrency is about guaranteeing capacity and throttling — it does not reduce cold starts. The exam mixes these up on purpose.
Lambda in a VPC, and Destinations
By default, Lambda functions run outside your VPC with internet access. Attach a function to a VPC (to reach a private RDS database, for example) and one big thing changes: the function loses default internet access — it needs a NAT gateway in a public subnet with proper route tables to reach the public internet. (VPC cold starts were historically longer because Lambda attached an ENI per function, but AWS has largely eliminated that penalty with pre-created managed network interfaces — don't pick "VPC ENI delay" as a modern root cause.) Destinations handle what happens after an asynchronous invocation. When Lambda is invoked asynchronously (S3 events, SNS, EventBridge), it retries twice on failure and then discards the event — unless you configure a destination: send successful results to one SQS queue or SNS topic, and failures to another. Destinations are the modern replacement for the older dead-letter queue setting, and they work for success cases too, not just failures.
Container Images and EFS: When Zip Isn't Enough
Standard Lambda deployment packages are capped at 250 MB unzipped — fine for most code, but not for a machine-learning model or heavy native dependencies. Lambda container images raise the ceiling to 10 GB : package the function as a container image, push it to ECR , and Lambda runs it with the same event-driven model and pricing. The exam signal is size — "package exceeds the limit" or "needs a large model file" points to container images. EFS for Lambda solves a different problem: shared, persistent file space. Mount an EFS file system and every concurrent execution sees the same files — model weights, reference datasets, shared configuration. EFS requires the function to run in a VPC. The exam's distinction: scratch space for a single invocation lives in /tmp (up to 10 GB, ephemeral); files that must persist or be shared across executions live on EFS.
Package too big container image (10 GB via ECR). Files shared or persistent across executions EFS (requires VPC). Temporary scratch for one invocation /tmp.
Amazon API Gateway: The Front Door
Amazon API Gateway is the managed service for creating, publishing, and securing HTTP APIs. Your mobile app or web frontend calls API Gateway; API Gateway calls your backend (usually Lambda). It handles the undifferentiated heavy lifting: request routing, throttling, caching, and API keys.
REST vs. HTTP vs. WebSocket APIs
API Gateway offers three API types, and choosing correctly is pure exam material. REST APIs are the full-featured option: request/response transformation, all authorization types (IAM, Cognito, Lambda authorizers), usage plans with API keys, and caching. They cost the most per request. HTTP APIs are the cheaper, faster, simpler option for proxy-style workloads. They support a subset of features (JWT authorizers, CORS) at roughly a third of the price of REST APIs. If a scenario describes a simple Lambda-backed API with no transformation needs and mentions cost, HTTP API is the answer. WebSocket APIs are for bidirectional, persistent connections — chat applications, live dashboards, multiplayer games. The client opens a connection once, and both sides can push messages. If the scenario says "real-time" and "two-way," think WebSocket.
Proxy Integration vs. Mapping Templates
The most-tested API Gateway concept is Lambda proxy integration . With proxy integration, API Gateway passes the entire HTTP request to Lambda — headers, query strings, path parameters, body — in a standard event format, and Lambda returns a standard response object with statusCode, headers, and body. No configuration needed; it just works. The vast majority of Lambda-backed APIs use proxy integration. Mapping templates (written in VTL — Velocity Template Language ) are for the opposite case: when you need to transform the request before it reaches the backend, or reshape the response. Custom (non-proxy) integration with mapping templates lets you rename fields, strip sensitive data, or adapt a legacy backend's format. The exam's signal phrase is "transform" — if the requirement mentions transforming request or response payloads, proxy integration is wrong and mapping templates are right.
Stages, Throttling, and Caching
An API Gateway stage (dev, prod) is a named snapshot of your API configuration — you deploy to a stage, and each stage gets its own invoke URL. Canary deployments on stages let you shift a percentage of traffic to a new deployment. Throttling protects your backend: API Gateway returns HTTP 429 when requests exceed the configured rate. U sage plans bundle throttling limits with quotas and associate them with API keys — the standard answer for "limit each customer to 1,000 requests per day." Caching stores responses at the stage level to reduce backend load. You can invalidate the cache per-request by having clients send Cache-Control: max-age=0. One hard limit the exam never stops testing: the integration timeout is 29 seconds , fixed and unchangeable. If your Lambda runs longer than 29 seconds behind API Gateway, the client gets a 504 no matter what you configure.
"Client receives 504 from API Gateway, Lambda runs 40 seconds" — the answer is the 29-second integration timeout, and the fix is to make the backend faster or go asynchronous. There is no setting that raises it.
Exercise 1. A developer's API Gateway REST API uses Lambda proxy integration. A new requirement says: strip the internal-debug header from every request before it reaches Lambda, and rename the userId field to customer_id in the JSON body. What should the developer change? Answer: Switch from proxy integration to a custom integration with mapping templates (VTL). Proxy integration passes the request through untouched by design — it cannot transform anything. Why not keep proxy and filter in Lambda code? Because the requirement is a gateway concern, and doing it in every function duplicates logic. Why not just add a stage? Stages version the API; they do not transform payloads.
Exercise 2. A Lambda function is triggered by an SQS queue. During a sale, some messages are processed twice, charging customers double. The developer increases the batch size to 10 and enables provisioned concurrency, but duplicates continue. What is the real fix? Answer: Make the function idempotent — SQS (like all event source mappings) delivers at-least-once, so duplicates are expected behavior, not a bug to tune away. Why didn't batch size help? It changes how many records arrive per invocation, not delivery guarantees. Why didn't provisioned concurrency help? It reduces cold starts; it has nothing to do with duplicate delivery.
Amazon DynamoDB: The Developer's Database
DynamoDB is AWS's managed NoSQL database: single-digit-millisecond reads at any scale, with no servers to manage. For a developer, four ideas unlock everything: keys, capacity, indexes, and consistency.
Keys and Capacity Math
Every DynamoDB table has a partition key (required), and optionally a sort key . The partition key determines which storage partition holds the item; the sort key orders items within a partition and enables queries like "all orders for customer X in January." A hot partition — one partition key receiving far more traffic than others — is the classic DynamoDB performance problem; the fix is a better-distributed key design, not more throughput. Capacity is measured in read and write capacity units . One RCU = one strongly consistent 4 KB read per second (or two eventually consistent 4 KB reads). One WCU = one 1 KB write per second. The exam's favorite math: a 2 KB item written 50 times per second needs 100 WCUs (each item costs 2 WCUs because of its size). With provisioned mode you declare capacity and pay for it; with on-demand mode you pay per request and DynamoDB scales automatically — better for spiky, unpredictable workloads.
GSI vs. LSI: The Index Trap
Global secondary indexes (GSIs) let you query on different key attributes. They have their own provisioned throughput, can be created at any time, and reads are always eventually consistent . Local secondary indexes (LSIs) share the table's partition key but use a different sort key; they must be created at table creation time (you cannot add one later), share the table's throughput, and support strongly consistent reads. The exam's trap is always the same: a scenario asks for an index added to an existing table with strongly consistent reads — impossible, because only LSIs offer strong consistency and only GSIs can be added later. You must pick your tradeoff.
DAX, Transactions, Streams, and TTL
DAX (DynamoDB Accelerator) is a managed in-memory cache in front of DynamoDB that drops read latency to microseconds. Use it when reads are the bottleneck — it does nothing for write-heavy workloads. Transactions (TransactWriteItems, up to 100 items) give all-or-nothing writes across items and tables — the answer whenever a scenario says "both writes must succeed or both must fail." DynamoDB Streams capture item-level changes in near-real time (records kept 24 hours) and pair naturally with Lambda event source mappings for reactive processing. Remember the pull-model rules: at-least-once delivery, ordering per shard. TTL (Time to Live) automatically deletes items after a timestamp you set — the serverless answer to "expire sessions after 30 days" without a cleanup job.
GSI = add anytime, own throughput, eventually consistent only. LSI = creation time only, shared throughput, strongly consistent possible. If a question asks for both "add later" and "strongly consistent," no index satisfies it — recognize the trap.
Query vs. Scan, Conditional Writes, and Pagination
Query finds items using the partition key plus an optional sort-key condition — it touches only the items you asked for and is the efficient read path. From the CLI, a query looks like this:
aws dynamodb query \
--table-name Orders \
--key-condition-expression "customerId = :cid" \
--expression-attribute-values '{":cid": {"S": "cust-4821"}}'
"All or nothing" transactions. "Don't overwrite an existing item" conditional write. "Concurrent writers, last-write-wins is wrong" optimistic locking with a version number. "Results stop after 1 MB" paginate with LastEvaluatedKey.
ElastiCache: Caching Strategies
ElastiCache (Redis or Memcached) sits in front of your database to absorb read traffic — the general-purpose answer where DAX is DynamoDB-only. Two strategies dominate exam questions. Lazy loading (cache-aside): the app checks the cache first; on a miss it reads the database and then populates the cache. Simple, and the cache holds only requested data — but the first request after an expiry pays the full database cost. Write-through : the app writes to the cache and the database together, so the cache is never stale — at the price of caching data nobody may read. Give cached items a TTL so stale entries expire on their own. The exam's signal: "cut database read load, brief staleness is fine" -> lazy loading; "the cache must never serve stale data" -> write-through.
DAX = DynamoDB-only read cache. ElastiCache = any database. Lazy loading = populate on miss; write-through = write both, never stale.
Amazon S3 for Developers
Developers meet S3 in three exam scenarios. Presigned URLs grant temporary access to a private object — a mobile app uploads directly to S3 using a URL your backend signs with SigV4. They expire — the SigV4 maximum of 7 days applies when signing with IAM user credentials; credentials from a role are limited by the session duration, which is usually much shorter. Whoever holds the URL can use it, so keep lifetimes short. S3 event notifications trigger Lambda (or SNS/SQS) on object events like s3:ObjectCreated:* — the standard pattern for "process every uploaded file." Multipart upload splits large files into parts uploaded in parallel; it is required for objects over 5 GB and recommended over 100 MB, and it lets failed parts retry individually instead of restarting the whole upload.
Messaging and Orchestration: SQS, SNS, EventBridge, Step Functions
SQS is the message queue: producers send messages, consumers poll and process. Messages stay until deleted, with a visibility timeout (default 30 seconds, max 12 hours) hiding a message from other consumers while it is being processed — set it longer than your processing time or messages reappear and get double-processed. Long polling (up to 20 seconds) reduces empty receives and cost. FIFO queues guarantee ordering and exactly-once processing (within a message group); standard queues are at-least-once and best-effort ordering. A dead-letter queue with a maxReceiveCount catches poison messages. SNS is pub/sub fan-out: one message published to a topic reaches all subscribers (Lambda, SQS, email, SMS). SQS decouples with polling; SNS pushes to many. EventBridge is the event bus for the whole AWS account: AWS services emit events, and rules route matching events to targets. It is the serverless answer to "when X happens anywhere, do Y" — including SaaS integrations and scheduled rules. Step Functions orchestrate multi-step workflows. Standard workflows run up to a year with exactly-once semantics — for business processes. Express workflows run up to 5 minutes with at-least-once semantics — for high-volume, short tasks like stream processing. Built-in retries with exponential backoff handle transient failures per state.
Queue (SQS) = pull, decouple, one consumer group processes each message. Topic (SNS) = push, fan-out to many. Event bus (EventBridge) = pattern-match events across services. Workflow (Step Functions) = ordered steps with retries. The exam describes the shape of the problem; match the shape.
Kinesis Data Streams: Ordered Event Ingest
Kinesis Data Streams ingest high-volume, ordered event data — clickstreams, IoT telemetry, application logs. Producers write records with a partition key ; records sharing a key land in the same shard and stay in order. Consumers — including Lambda via event source mappings — read per shard. Stream data persists 24 hours by default and up to 365 days , so unlike SQS (where a deleted message is gone), a stream is a replayable log : re-process yesterday's events after fixing a bug. Enhanced fan-out gives each consumer its own dedicated read throughput instead of sharing the shard's limit. The exam distinguishes Kinesis from SQS by shape: "process events in order per customer and re-play the last day after an outage" is Kinesis; "decouple a web tier from workers, each message processed once by one consumer" is SQS.
Amazon Cognito: User Pools vs. Identity Pools
Cognito user pools are user directories: sign-up, sign-in, MFA, password policies. Your app authenticates users against the pool and receives JWTs — an ID token (who the user is), an access token (what they may do), and a refresh token (opaque, used to get new tokens). Use user pools when your app needs its own login system. Cognito identity pools (federated identities) do something different: they exchange an authenticated identity — from a user pool, Google, Facebook, or even guest access — for temporary AWS credentials . Use identity pools when your app's users need direct, scoped access to AWS resources (upload to their own S3 folder, read their own DynamoDB rows). The exam's signal: "mobile users need temporary AWS credentials" = identity pool. "App needs login with MFA" = user pool. They are frequently used together: user pool authenticates, identity pool authorizes AWS access.
SDKs and the CLI
The AWS SDKs let your code call AWS services; the AWS CLI lets you (and scripts) do it from the terminal. Two developer-relevant facts. First, the credential provider chain : SDKs look for credentials in a fixed order — environment variables, shared credentials file, then (on EC2/ECS/Lambda) the instance/task/execution role. On Lambda, the execution role always wins, which is why hardcoding keys is both unnecessary and dangerous. Second, the CLI's --query (JMESPath) filters JSON output — the exam occasionally tests that you know output can be shaped without extra tools.
Exercise 3. A mobile app lets users sign in with email and MFA, and signed-in users must upload profile photos directly to an S3 bucket under profiles/{user-id}/. Which Cognito setup meets both needs? Answer: A user pool for sign-in (MFA, password policy) federated into an identity pool that vends temporary AWS credentials scoped to profiles/{user-id}/. Why not just a user pool? User pools issue JWTs, not AWS credentials — the app could not call S3 directly. Why not just an identity pool? Identity pools do not provide a login UI or MFA; they exchange an existing identity for credentials. Why not IAM users per mobile user? Unmanageable at scale and a credential-management nightmare.*
Exercise 4. A developer needs an API that (a) transforms incoming XML orders into JSON before they reach Lambda, (b) limits each partner to 5,000 requests per day, and (c) keeps costs low for a simple proxy workload on the remaining endpoints. Which combination fits? Answer: REST API with mapping templates (VTL) for the XML endpoint — transformation requires custom integration, not proxy. Usage plans with API keys and throttling for the per-partner quota. HTTP API for the simple proxy endpoints to cut cost. Why not proxy integration everywhere? Proxy cannot transform payloads. Why not REST for everything? HTTP APIs cost roughly a third of REST for plain proxy workloads.
End-of-Chapter Test
1. A Lambda function processes images uploaded to S3. During a flash sale, thousands of uploads arrive per minute, and the function must keep up without throttling while a downstream thumbnail API accepts only 50 concurrent connections. Which concurrency configuration should the developer use? A) Provisioned concurrency set to 50 B) Reserved concurrency set to 50 C) Unreserved account concurrency with no function-level setting D) Reserved concurrency set to 5,000
2. A team deploys a new version of a Lambda function behind API Gateway. They want 10% of live traffic on the new version for one hour, with instant rollback if errors spike — and no extra infrastructure. What should they use? A) Create a second Lambda function and split traffic between the two in API Gateway B) Enable provisioned concurrency on the new version C) Publish a new version and configure the prod alias with 90/10 weighted routing D) Publish the code to $LATEST and shift the alias when confident
3. A DynamoDB table has been in production for two years. The product team wants a new feature: look up orders by customerEmail. Lookups can tolerate data a few seconds old. Which approach works? A) Add a GSI on customerEmail B) Add an LSI on customerEmail C) Scan the table filtering on customerEmail D) Create a new table with customerEmail as the partition key and migrate all data
4. A developer generates a presigned URL so a partner can download a private S3 report. The partner needs access for 10 days. What should the developer do? A) Generate the presigned URL with a 10-day expiration B) Generate the presigned URL with the maximum 7-day expiration and re-issue it when it lapses C) Make the object public for 10 days, then make it private again D) Create an IAM user for the partner with GetObject permission
5. A leaderboard service writes player scores to DynamoDB. When two players finish at the same moment, one player's increment must not silently overwrite the other's — every increment has to apply to the latest value. Which write pattern guarantees this? A) Read the item's version number, then write back with a condition that the version is unchanged, retrying on ConditionalCheckFailedException B) Put both increments in a single BatchWriteItem call C) Enable DynamoDB Streams and reconcile the scores in a Lambda function D) Switch the table to on-demand capacity mode
6. A company runs a multi-step order workflow: validate payment, reserve inventory, schedule shipment, send confirmation. Each step calls a different Lambda function, and a failed step must retry with backoff before the workflow gives up. Which service fits best? A) EventBridge with rules routing each step B) SQS FIFO queue chaining the functions C) SNS topic with all four functions subscribed D) Step Functions Standard workflow
7. A mobile app authenticates users with social logins and needs each user to read and write only their own rows in a DynamoDB table directly from the device. Which approach is correct? A) Embed an IAM user's access keys in the app, scoped to the user's rows B) Use a Cognito user pool only, passing the ID token to DynamoDB C) Federate the social identity through a Cognito identity pool vending temporary credentials scoped to the user's rows D) Create one IAM role per user and hardcode the role ARN in the app
8. A developer stores database credentials for a Lambda function. The security team requires automatic rotation every 30 days and no credentials in code or environment variables. What is the correct solution? A) Store the password in a Lambda environment variable encrypted with the default key B) Store the credentials in a DynamoDB table read by the function C) Create a new IAM user each month and update the function's environment variables D) Store the credentials in AWS Secrets Manager with rotation enabled, retrieved at runtime
9. A Lambda function is invoked asynchronously by S3 event notifications. Occasionally the function fails, and the team needs failed events preserved for later analysis without losing successful results. Which configuration meets this requirement? A) Configure a dead-letter queue on the SQS event source mapping B) Configure Lambda destinations with an on-failure destination for failed invocations C) Increase the function's reserved concurrency to handle the failure spike D) Enable S3 event notification retries with exponential backoff
10. A developer's REST API serves a mobile app with predictable traffic. The backend Lambda functions are fast, but the team wants to reduce Lambda invocations for repeated identical GET requests. Which API Gateway feature should they enable? A) Request validation on the method request B) Stage-level caching with a TTL on the GET methods C) A usage plan with a higher throttling quota D) A Lambda authorizer with result caching
11. An application publishes order events to an SNS topic with two SQS queue subscribers. The inventory queue must receive only "order_created" events, while the analytics queue must receive all events. How should the developer configure this? A) Create a separate SNS topic for each event type B) Add an SNS filter policy on the inventory queue's subscription matching the eventType message attribute C) Configure the inventory queue as FIFO and the analytics queue as standard D) Enable content-based deduplication on the SNS topic
Answer Key
1. B — Reserved concurrency caps the function at 50 parallel executions, which both guarantees capacity and throttles the function so it never opens more than 50 connections to the downstream API. Why not A? Provisioned concurrency keeps instances warm (latency), but it does not cap the maximum — the function could still scale past 50 connections. Why not C? Unreserved concurrency lets the function scale to the account limit, overwhelming the 50-connection API. Why not D? 5,000 reserved would guarantee capacity but would not protect the downstream API at all. 2. C — Aliases are movable pointers, and weighted routing splits traffic between two versions with no extra infrastructure; moving the alias back is instant rollback. Why not A? A second function doubles the moving parts, and API Gateway has no native traffic-splitting between two functions. Why not B? Provisioned concurrency keeps instances warm (latency) — it does not shift traffic. Why not D? $LATEST is an unpublished, mutable pointer — there is no safe version to roll back to. 3. A — GSIs can be added to an existing table at any time and serve key-based lookups; eventual consistency is fine here since a few seconds of staleness is tolerated. Why not B? LSIs can only be created at table-creation time — impossible on a two-year-old table. Why not C? A Scan reads every item in the table — slow and expensive at production scale. Why not D? A full migration for a lookup is wildly disproportionate when a GSI solves it natively. 4. B — The SigV4 presigned-URL maximum is 7 days (for IAM user credentials; role credentials are limited by session duration). For 10 days of access, issue a 7-day URL and re-issue before it lapses. Why not A? The 7-day maximum is hard — the SDK will not sign a longer-lived URL. Why not C? Making the object public exposes it to the entire internet, violating least privilege for a partner-specific report. Why not D? Creating IAM users for external partners is an anti-pattern; it creates long-term credentials to manage and rotate. 5. A — This is optimistic locking: the version-number condition makes the write fail if another writer got there first, and the retry applies the increment to the fresh value. Why not B? BatchWriteItem reduces round trips but has no cross-item conditions and no rollback — one item can fail while the other succeeds. Why not C? Streams are asynchronous — they observe the overwrite after it happens; they cannot prevent it. Why not D? Capacity mode controls throughput and cost, not write correctness. 6. D — Step Functions Standard is built for exactly this: ordered multi-step workflows with per-state retries, exponential backoff, and up to a year of execution. Why not A? EventBridge routes events by pattern matching; it does not orchestrate ordered steps with retries. Why not B? SQS chaining can sequence work but has no built-in workflow state, retries with backoff, or visual tracking. Why not C? SNS delivers to all subscribers at once — parallel fan-out, the opposite of an ordered workflow. 7. C — The identity pool exchanges the social identity for temporary AWS credentials, and the associated role policy scopes DynamoDB access to the user's own rows (leading-key condition). No long-term secrets on the device. Why not A? Embedding IAM user keys in a mobile app exposes them to anyone who decompiles it. Why not B? A user pool issues JWTs for authentication; DynamoDB needs AWS credentials (SigV4), which JWTs are not. Why not D? One role per user does not scale and still leaves the credential-vending problem unsolved. 8. D — Secrets Manager supports automatic rotation on a schedule (30 days) and the function retrieves the secret at runtime — nothing in code or environment variables. Why not A? Environment variables are visible in plaintext in the console to anyone with read access, and there is no rotation. Why not B? A DynamoDB table is not a secrets store — no rotation, no audit trail for secret access. Why not C? Monthly manual user rotation is operational toil and still leaves the secret sitting in an environment variable. 9. B — Lambda destinations handle post-invocation routing for async calls — send failures to one SQS queue/SNS topic and successes elsewhere. Why not A? DLQs on event source mappings apply to stream/poll-based sources (Kinesis, DynamoDB Streams, SQS), not to async push invocations like S3 events. Why not C? Reserved concurrency caps scale; it does nothing for failed event preservation. Why not D? S3 delivers the notification once; retry behavior for async invocations is Lambda's domain, not S3's. 10. B — API Gateway caching stores responses at the stage level, so repeated identical GETs are served from cache without invoking Lambda. Why not A? Request validation rejects malformed requests; it does not cache responses. Why not C? Usage plans control throttling and quotas per API key — they do not reduce backend invocations. Why not D? Authorizer caching avoids re-running auth logic, not backend integrations. 11. B — SNS filter policies on message attributes let each subscription receive a different slice of one topic's traffic. Why not A? Separate topics per event type creates topic sprawl — filtering exists to avoid exactly this. Why not C? FIFO vs standard affects ordering and deduplication, not message routing. Why not D? Content-based deduplication is an SQS FIFO feature for duplicate suppression, not SNS subscription filtering — and filtering works on message attributes, not body content.
Answer key
Want the full AWS Developer – Associate (DVA-C02) package?
This guide is free to read. Get the downloadable PDF guidebook plus the full DVA-C02 practice exam with 3 months of online access.
Get DVA-C02 Full Access — $10