♻️ Zero-Based Review: Lambda Aggregator
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- Avg merge
- 6h 51m
- Merged PRs (30d)
- 104
Description
Description
A comprehensive zero-base review of the zae_limiter_aggregator package — the Lambda function that processes DynamoDB Streams for usage snapshots, proactive bucket refill, and audit event archival.
The aggregator is a critical production component (1,131 LOC across 4 modules) that runs as an AWS Lambda triggered by DynamoDB Streams. It handles three responsibilities:
- Usage snapshot aggregation — extracts consumption deltas from bucket MODIFY events and writes hourly/daily snapshot records
- Proactive bucket refill — refills buckets when projected tokens are insufficient for observed consumption rates (Issue #317)
- Audit event archival — archives TTL-deleted audit events to S3 as gzip-compressed JSONL with Hive-style partitioning
Modules Under Review
| Module | LOC | Responsibility |
|---|---|---|
handler.py |
131 | Lambda entry point, environment config, orchestration |
processor.py |
686 | Stream parsing, delta extraction, snapshot writes, bucket refill |
archiver.py |
291 | Audit event extraction, S3 archival with gzip JSONL |
__init__.py |
23 | Re-exports |
Test Coverage Under Review
| Test File | Tests |
|---|---|
tests/unit/test_handler.py |
5 tests — handler orchestration, archival toggle, error aggregation |
tests/unit/test_processor.py |
~45 tests — delta extraction, window keys, snapshots, refill, logging |
tests/unit/test_archiver.py |
~20 tests — audit extraction, deserialization, JSONL, S3 partitioning |
Acceptance Criteria
Code Quality & Structure
- All functions have docstrings with Args/Returns sections
- No dead code or unused imports exist in any aggregator module
- All
TODO,FIXME, orHACKcomments are resolved or tracked as issues - Type annotations are present on all function signatures and return types
- Dataclass fields have type annotations (no
Anywhere a concrete type is possible)
Error Handling & Resilience
- All DynamoDB
update_itemcalls have error handling that does not crash the batch -
ConditionalCheckFailedExceptionintry_refill_bucketis caught and logged at DEBUG (not WARNING or ERROR) - S3
put_objectfailure in archiver does not prevent snapshot processing - Extraction errors for individual records do not prevent processing of remaining records
- No bare
except Exceptionwithoutexc_info=Truein log calls
DynamoDB Patterns (ADR-111 Compliance)
- All DynamoDB expressions use flat schema (no nested
data.Mpaths) - Reserved words (
resource,window,window_start,ttl) useExpressionAttributeNamesaliases -
update_snapshotuses SET + ADD without overlapping document paths (Issue #168) - Refill
UpdateExpressionuses ADD for tokens (commutative with speculative writes) and SET forrf(optimistic lock)
Stream Record Parsing
-
_parse_bucket_recordcorrectly discovers limits by scanningb_{name}_tcattributes - Records with missing
entity_id, empty resource, or missingtccounters returnNone/empty list - Only MODIFY events are processed for deltas and refill; REMOVE events are processed for archival
- Partial counters (only OldImage or only NewImage has
tc) are skipped
Snapshot Aggregation
- Millitokens are converted to tokens (integer division by 1000) before storage
- GSI2 keys (GSI2PK, GSI2SK) are set for resource-level aggregation queries
- TTL is set using
if_not_exists(does not overwrite on subsequent ADD operations) - Window key functions produce correct ISO timestamps for hourly, daily, and monthly windows
-
get_window_endhandles December year rollover and leap years
Proactive Bucket Refill
-
aggregate_bucket_statesaccumulatestc_deltaacross multiple events for the same bucket -
aggregate_bucket_statesuses the last event's NewImage fields (tk, cp, bx, ra, rp) and rf timestamp - Refill is skipped when
refill_delta <= 0(no elapsed time or already at capacity) - Refill is skipped when
projected >= consumption_estimate(tokens sufficient for next window) - Negative
tc_delta(refunds) does not trigger refill (max(0, info.tc_delta)guard) - Multiple limits needing refill produce a single
UpdateItemcall (not one per limit) - Optimistic lock on
rfusesConditionExpression: rf = :expected_rf
Audit Archival
- Only REMOVE events with
AUDIT#PK prefix are extracted - Records missing the
actionfield are skipped with a WARNING log - DynamoDB wire format deserialization handles S, N, BOOL, NULL, M, and L types
- JSONL uses compact separators (
(",", ":")) for minimal S3 storage - S3 object key uses Hive-style partitioning (
audit/year=YYYY/month=MM/day=DD) - Timestamp sanitization removes colons and plus signs from S3 filenames
- Content-Type is
application/x-ndjsonand Content-Encoding isgzip
Handler Orchestration
- Environment variables have sensible defaults (
TABLE_NAME=rate-limits,SNAPSHOT_WINDOWS=hourly,daily,SNAPSHOT_TTL_DAYS=90) - Archival is skipped when
ENABLE_ARCHIVAL=falseORARCHIVE_BUCKET_NAMEis empty - S3 client is only created when archival is enabled (no unnecessary boto3 calls)
- Processing time is measured with
time.perf_counter()and logged in milliseconds - Empty records list returns early with zero counts (no DynamoDB/S3 calls)
- Errors from snapshot processing and archival are aggregated into a single response
Logging
-
StructuredLoggeroutputs valid JSON to stdout (CloudWatch Logs Insights compatible) - All log entries include
timestamp,level,logger, andmessagefields - Error/warning logs include
exc_info=Truewithexceptionfield containing traceback - Batch processing logs start and completion with
processing_time_msmetric - Debug logs for individual snapshot updates include
entity_id,resource,limit_name,window
Test Quality
- Unit tests use mocks (not moto) for DynamoDB and S3 calls
- Test helpers (
_make_record,_make_bucket_record,_make_audit_record) produce flat schema records (ADR-111) - Edge cases tested: empty records, zero delta, missing fields, partial counters, invalid data
- Refill tests verify ADD vs SET in UpdateExpression, optimistic lock, and conditional check failure
- Archival tests verify gzip decompression, JSONL parsing, S3 headers, and error recovery
- No test relies on specific DynamoDB wire format that could drift from production schema
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the four modules in the zae_limiter_aggregator package: handler.py, processor.py, archiver.py, and init.py, then run the listed unit tests. Review each acceptance-criteria section against the implementation and existing tests. Done means the aggregator behavior, resilience, schema patterns, logging, and test coverage satisfy the specified checks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, python
- Domain
- backend, cloud, databases, testing-qa
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100