This page requires JavaScript to display.
L
Unpacking...
← Cloud Platforms
Cloud Platforms

AWS Lambda for Data Engineers

Limits and invocation models, S3/SQS/Kinesis handler examples, packaging and deployment, configuration and secrets, idempotency, observability and anti-patterns.

Contents
1. What AWS Lambda Is 2. Invocation Models 3. Example: Validate a File and Start a Pipeline 4. Example: Batch Processing from SQS 5. Example: Kinesis Stream Consumer 6. Packaging & Deployment 7. Configuration, Secrets & Networking 8. Idempotency, Observability & Anti-Patterns 9. Common Interview Questions

1. What AWS Lambda Is

AWS Lambda runs your function in response to events without servers to manage. You pay per request and per GB-second of execution. In data engineering it is the glue for short, event-driven steps: validate a file, start a job, route a message, call an API, send an alert.

LimitValue
Maximum run time15 minutes per invocation
Memory128 MB – 10,240 MB (CPU scales with memory; about 1 vCPU at 1,769 MB)
Ephemeral /tmp storage512 MB by default, configurable up to 10 GB
Deployment package50 MB zipped upload (250 MB unzipped, including layers); container images up to 10 GB
Concurrency1,000 concurrent executions per region by default (can be raised)
Payload6 MB for synchronous requests; asynchronous events are smaller (check current docs)

2. Invocation Models

ModelExamplesRetries and failures
SynchronousAPI Gateway, function URLs, SDK invokeCaller sees the error and decides
AsynchronousS3 notifications, SNS, EventBridgeLambda retries twice; then send to an on-failure destination or DLQ
Poll-based (event source mapping)SQS, Kinesis, DynamoDB Streams, MSK/KafkaLambda polls and batches; failures retry per batch, with partial-batch responses, bisecting and DLQs

3. Example: Validate a File and Start a Pipeline

import json, os, urllib.parse
import boto3

s3 = boto3.client("s3")
sfn = boto3.client("stepfunctions")
STATE_MACHINE_ARN = os.environ["STATE_MACHINE_ARN"]  # configuration via environment variables
MAX_BYTES = 5 * 1024 ** 3

def handler(event, context):
    for record in event["Records"]:  # one S3 event can contain several records
        bucket = record["s3"]["bucket"]["name"]
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])  # keys arrive URL-encoded
        head = s3.head_object(Bucket=bucket, Key=key)

        if not key.endswith(".csv.gz") or head["ContentLength"] == 0 or head["ContentLength"] > MAX_BYTES:
            s3.copy_object(Bucket=bucket, Key=f"_quarantine/{key}", CopySource={"Bucket": bucket, "Key": key})
            print(json.dumps({"level": "WARN", "msg": "rejected file", "key": key}))
            continue

        sfn.start_execution(
            stateMachineArn=STATE_MACHINE_ARN,
            name=f"load-{head['ETag'].strip(chr(34))}",  # same file → same name → no duplicate run
            input=json.dumps({"bucket": bucket, "key": key, "size": head["ContentLength"]}),
        )
    return {"status": "ok"}

Using the object ETag in the execution name makes the trigger idempotent: if S3 delivers the same event twice, Step Functions rejects the duplicate name for a Standard workflow.

4. Example: Batch Processing from SQS

import json

def handler(event, context):
    failures = []
    for record in event["Records"]:
        try:
            msg = json.loads(record["body"])
            process(msg)  # your logic; must be idempotent
        except Exception as exc:
            print(f"failed {record['messageId']}: {exc}")
            failures.append({"itemIdentifier": record["messageId"]})
  # only the failed messages return to the queue; the rest are deleted
    return {"batchItemFailures": failures}
Event source mapping settingPurpose
Batch size / batching windowHow many records per invocation, and how long to wait to fill a batch
ReportBatchItemFailuresEnables the partial-batch response shown above
Maximum concurrency (SQS)Caps parallel invocations to protect downstream databases
Bisect batch on error (streams)Splits a failing Kinesis/DynamoDB batch to isolate the poison record
Destinations / DLQWhere records go after all retries fail

Set the SQS visibility timeout to at least six times the function timeout, or messages reappear while still being processed.

5. Example: Kinesis Stream Consumer

import base64, json

def handler(event, context):
    rows = []
    for record in event["Records"]:
        payload = base64.b64decode(record["kinesis"]["data"])  # data arrives base64-encoded
        txn = json.loads(payload)
        if txn.get("amount", 0) > 100000:
            rows.append(txn)
    if rows:
        write_alerts(rows)  # e.g. DynamoDB batch_writer
    return {"batchItemFailures": []}

6. Packaging & Deployment

# zip deployment with dependencies
pip install -r requirements.txt -t package/
cp handler.py package/ && (cd package && zip -r ../function.zip .)
aws lambda create-function --function-name file-validator \
  --runtime python3.12 --handler handler.handler --architectures arm64 \
  --role arn:aws:iam::111122223333:role/file-validator-role \
  --memory-size 512 --timeout 60 --zip-file fileb://function.zip \
  --environment "Variables={STATE_MACHINE_ARN=arn:aws:states:ap-south-1:111122223333:stateMachine:daily-load}"

aws lambda update-function-code --function-name file-validator --zip-file fileb://function.zip
aws lambda invoke --function-name file-validator --payload fileb://test_event.json out.json

7. Configuration, Secrets & Networking

TopicGuidance
Execution roleLeast privilege: only the S3 prefixes, queues and APIs the function needs
SecretsRead from Secrets Manager or Parameter Store at cold start and cache in a global variable; never put secrets in plain environment variables
VPC accessAttach to private subnets to reach RDS or internal services; add VPC endpoints or a NAT gateway for AWS APIs and the internet
Database connectionsUse RDS Proxy: thousands of concurrent functions would otherwise exhaust database connections
Reserved concurrencyGuarantees and caps concurrency for one function (also a quick "off switch" at 0)
Provisioned concurrency / SnapStartPre-initialised environments to remove cold starts for latency-sensitive paths
TimeoutSet close to real need; the default is only 3 seconds

8. Idempotency, Observability & Anti-Patterns

Anti-patternDo instead
Heavy ETL or large joins in LambdaGlue, EMR, or Fargate; Lambda only starts them
Work that may exceed 15 minutesStep Functions orchestrating Glue/EMR/Batch, or split the work (Distributed Map)
A function that invokes itself in a loopStep Functions; AWS detects and stops recursive loops
Writing back into the prefix that triggers the functionWrite to a different prefix or bucket
Opening a new DB connection per invocationReuse connections outside the handler, and use RDS Proxy

9. Common Interview Questions

QuestionShort answer
What are Lambda's key limits?15-minute timeout, up to 10 GB memory and /tmp, deployment size limits, payload limits and account concurrency
How do you handle work longer than 15 minutes?Hand it to Glue, EMR, Batch or Fargate and orchestrate with Step Functions, or split it into smaller parallel units
What is a cold start, and how do you reduce it?Initialising a new execution environment; reduce with smaller packages, lazy imports, provisioned concurrency or SnapStart
How do retries work for async invocations?Two retries with backoff, then an on-failure destination or DLQ; for SQS/stream sources, retries are per batch
What is a partial batch response?Returning batchItemFailures so only failed SQS/stream records are retried instead of the whole batch
How do you connect Lambda to RDS safely?Run in the VPC, use RDS Proxy for connection pooling, IAM authentication or Secrets Manager credentials
How do you make a Lambda idempotent?Deterministic keys and conditional writes, or record processed event IDs in DynamoDB before acting