119 lines
11 KiB
Markdown
119 lines
11 KiB
Markdown
---
|
|
title: AWS Lambda Powertools — Idempotency utility (DynamoDB + payload hash)
|
|
source_type: official-doc
|
|
url: https://docs.aws.amazon.com/powertools/python/latest/utilities/idempotency/
|
|
archive_url:
|
|
status: raw
|
|
confidence: high
|
|
tags: [ca-idempotency, aws-lambda, content-hash, dynamodb, body-fingerprint, official-doc]
|
|
related_projects: [ca-skeleton-operational-contract]
|
|
related_branches: [feature-rate-limit-idempotency-contract, feature-api-contract-baseline]
|
|
created: 2026-05-22
|
|
last_reviewed: 2026-05-27
|
|
---
|
|
|
|
# AWS Lambda Powertools — Idempotency utility
|
|
|
|
> Layer: `raw/official-docs/` — AWS Lambda Powertools (Python) 공식 utility 문서 발췌. ca-tmpl Topic 5 Idempotency 의 대안 3 (content-hash / server-derived key) 모델의 1차 근거.
|
|
|
|
## Parent / 활용 branch (필수)
|
|
|
|
| Branch | 이 자료가 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/branch-notes/feature-rate-limit-idempotency-contract]] | "content-hash 기반 server-derived key" 대안의 reference implementation 비교 근거 — ca-tmpl이 client-supplied key 모델을 채택한 이유의 대조군 |
|
|
| [[raw/branch-notes/feature-api-contract-baseline]] | API contract baseline 에서 Idempotency-Key 헤더 정책을 명문화할 때 "다른 가능한 모델"의 예시 (server hash vs client key) |
|
|
|
|
## 컨텍스트 / 왜 저장했는지
|
|
|
|
ca-tmpl의 대안 4번 **"request content hash 기반 (body SHA-256 = idempotency key)"** 의 대표 reference implementation. 클라이언트가 key를 안 보내도 서버가 payload hash로 dedup하는 모델. ca-tmpl의 client-supplied key + body fingerprint mismatch 정책 결정의 대조군.
|
|
|
|
## 출처 / Source
|
|
|
|
- 원본 URL: https://docs.aws.amazon.com/powertools/python/latest/utilities/idempotency/
|
|
- 아카이브 URL: (미수집)
|
|
- 저자 / 조직: AWS (Powertools for AWS Lambda team)
|
|
- 발행일: rolling docs (Python Powertools current)
|
|
- 마지막 확인일: 2026-05-27
|
|
- 보조: AWS compute blog "Handling Lambda functions idempotency with AWS Lambda Powertools" / TypeScript 버전
|
|
|
|
## 핵심 인용 / Key quotes (verbatim)
|
|
|
|
> [§Terminology] "Idempotency key By default, this is a combination of (a) Lambda function name, (b) fully qualified name of your function, and (c) a hash of the entire payload or part(s) of the payload you specify. However, you can customize the key generation by using (a) a custom prefix name, while still incorporating (c) a hash of the entire payload or part(s) of the payload you specify."
|
|
|
|
> [§Getting started → Required resources] "Primary key for any persistence storage: We combine the Lambda function name and the fully qualified name for classes/functions to prevent accidental reuse for similar code sharing input/output. Primary key sample: `{lambda_fn_name}.{module_name}.{fn_qualified_name}#{idempotency_key_hash}`"
|
|
|
|
> [§Adjusting expiration window] "By default, we expire idempotency records after an hour (3600 seconds). After that, a transaction with the same payload will not be considered idempotent."
|
|
|
|
> [§Handling concurrent executions with the same payload] "This utility will raise an `IdempotencyAlreadyInProgressError` exception if you receive multiple invocations with the same payload while the first invocation hasn't completed yet."
|
|
|
|
> [§Handling concurrent executions with the same payload] "If you receive `IdempotencyAlreadyInProgressError`, you can safely retry the operation. This is a locking mechanism for correctness. Since we don't know the result from the first invocation yet, we can't safely allow another concurrent execution."
|
|
|
|
> [§Payload validation] "With `payload_validation_jmespath`, you can provide an additional JMESPath expression to specify which part of the event body should be validated against previous idempotent invocations"
|
|
|
|
> [§Payload validation] "Note: If we try to send the same request but with a different amount, we will raise `IdempotencyValidationError`."
|
|
|
|
## Claims Extracted / 추출된 주장
|
|
|
|
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
|
|---|---|---|---|---|---|
|
|
| IDMP-AWS-C1 | Powertools 의 idempotency key 는 기본적으로 (a) Lambda 함수명, (b) fully qualified function name, (c) payload 전체 또는 일부의 hash 의 조합으로 server-side derive 됨 | [§Terminology] "Idempotency key By default, this is a combination of (a) Lambda function name, (b) fully qualified name of your function, and (c) a hash of the entire payload or part(s) of the payload you specify." | `official-vendor-doc` | AWS Lambda Powertools (Python) idempotency utility 기본 설정 | 모든 idempotency 모델이 이렇게 동작한다는 뜻은 아님 — 본 utility 한정. client-supplied key 모델 (Stripe/PayPal/ca-tmpl) 은 다른 접근 |
|
|
| IDMP-AWS-C2 | DynamoDB 영속 저장소의 primary key sample 은 `{lambda_fn_name}.{module_name}.{fn_qualified_name}#{idempotency_key_hash}` 형식이며, 코드 공유 시 우발적 키 충돌 방지가 목적 | [§Getting started → Required resources] "Primary key sample: `{lambda_fn_name}.{module_name}.{fn_qualified_name}#{idempotency_key_hash}`" | `official-vendor-doc` | DynamoDB 백엔드 사용 시 | Redis/Valkey 백엔드의 key schema 는 본 인용 범위 밖 |
|
|
| IDMP-AWS-C3 | Idempotency 레코드의 기본 TTL 은 3600초 (1시간) 이며, 그 이후 같은 payload 트랜잭션은 더 이상 idempotent 로 간주되지 않음 | [§Adjusting expiration window] "By default, we expire idempotency records after an hour (3600 seconds). After that, a transaction with the same payload will not be considered idempotent." | `official-vendor-doc` | Powertools 기본 설정 | "3600초가 결제 도메인에서 충분하다" 는 권고는 아님 — Stripe 24h / ca-tmpl 24h 와 비교 시 짧음. `expires_after_seconds` 로 조정 가능 |
|
|
| IDMP-AWS-C4 | 같은 payload 의 first invocation 이 완료되기 전 동일 payload 의 다른 invocation 이 들어오면 `IdempotencyAlreadyInProgressError` 예외가 raise 됨 (in-flight lock 메커니즘) | [§Handling concurrent executions with the same payload] "This utility will raise an `IdempotencyAlreadyInProgressError` exception if you receive multiple invocations with the same payload while the first invocation hasn't completed yet." | `official-vendor-doc` | 동시 invocation 시 | "wait + 재시도" 와 같은 graceful 처리가 utility 내부에 빌트인 되어 있다는 뜻은 아님 — 호출자가 catch 후 retry 책임 |
|
|
| IDMP-AWS-C5 | `payload_validation_jmespath` 옵션을 사용하면 event body 의 특정 부분만 이전 invocation 과 비교 검증 가능. 다른 값이면 `IdempotencyValidationError` raise | [§Payload validation] "With `payload_validation_jmespath`, you can provide an additional JMESPath expression to specify which part of the event body should be validated against previous idempotent invocations" + "Note: If we try to send the same request but with a different amount, we will raise `IdempotencyValidationError`." | `official-vendor-doc` | payload_validation_jmespath 활성화 시 | 이 검증이 default 동작이라는 뜻은 아님 — 명시적 옵트인 필요. ca-tmpl 의 body fingerprint mismatch 422 정책과 의미는 같으나 status code/HTTP 매핑은 호출자 책임 |
|
|
|
|
## Usage Boundaries / 적용 경계
|
|
|
|
- **이 자료가 직접 증명하는 것**:
|
|
- `IDMP-AWS-C1`: server-derived key 모델의 정확한 컴포지션 (함수명 + FQ name + payload hash)
|
|
- `IDMP-AWS-C2`: DynamoDB primary key 형식
|
|
- `IDMP-AWS-C3`: 기본 TTL 3600초
|
|
- `IDMP-AWS-C4`: in-flight 동시 호출 시 즉시 exception raise
|
|
- `IDMP-AWS-C5`: jmespath 기반 부분 검증 + mismatch 시 exception
|
|
- **이 자료가 증명하지 않는 것**:
|
|
- "content-hash 모델이 client-supplied key 모델보다 안전하다" 는 권고 (본 utility 의 설계 선택일 뿐, 도메인 적합성은 별도 판단)
|
|
- body 의 JSON 직렬화 차이 (필드 순서, 공백, escape) 가 hash 에 미치는 영향 — 본 인용에 명시 없음
|
|
- 결제 도메인에서 1시간 TTL 이 충분한지 — 본 인용은 단지 default 값만 제시
|
|
- in-flight error 발생 시 client 가 어떤 backoff 정책을 써야 하는지 — utility 외부 책임
|
|
- **내 프로젝트에 적용하려면 추가 확인이 필요한 것**:
|
|
- ca-tmpl 의 client-supplied key + 422 정책이 server-hash 모델 대비 어떤 도메인에서 우위인지 (ca-tmpl 본문에서 별도 논증 필요)
|
|
- DynamoDB TTL 컬럼 vs Redis EXPIRE 의 실제 운영 비용 비교 (대안 그룹 보조 source 필요)
|
|
|
|
## 메모 / Notes (내 프로젝트 해석)
|
|
|
|
> 본 섹션은 자료 직접 인용 아님. ca-tmpl 결정 컨텍스트 해석.
|
|
|
|
- **key scope (어떤 dimension으로):** `(function_name, fully_qualified_fn_name, payload_hash)`. 가맹점/principal 개념은 별도로 안 들어가고 **함수 단위 + body hash**가 자연스러운 scope. 헤더에서 키 추출도 가능 (`X-Idempotency-Key`).
|
|
- **저장소:** DynamoDB (default), Redis/Valkey (alt). **ca-tmpl이 DB table을 쓴 것과 같은 계열의 영속 저장 선택**.
|
|
- **duplicate 처리:**
|
|
- 완료된 동일 hash → first response 그대로 반환.
|
|
- in-flight → `IdempotencyAlreadyInProgressError` (lock 기반).
|
|
- **fingerprint (same key, different body) — 두 가지 모델 동시 지원**:
|
|
1. payload 전체가 key (hash로 자동 분기) → 다른 body면 그냥 다른 키로 취급, dedup 안 됨.
|
|
2. 일부만 key + `payload_validation_jmespath`로 검증 → 다르면 `IdempotencyValidationError`.
|
|
- **장점:**
|
|
- 클라이언트 협조 없이도 서버 단독으로 dedup 가능 (key 미제공도 hash로 처리).
|
|
- DynamoDB TTL로 만료 운영비 거의 0.
|
|
- in-flight lock + 만료 timeout으로 좀비 lock 방지.
|
|
- **단점:**
|
|
- body hash 모델은 "의미상 동일하나 직렬화가 다른 요청" (필드 순서, 공백 등) → 다른 키로 분기되어 dedup 누수.
|
|
- 클라이언트가 retry할 때 body를 한 글자라도 바꾸면 새 요청으로 인식됨.
|
|
- 명시적 422가 아니라 exception → 호출자가 catch 후 5xx로 위장하는 예시 코드 권장 → 의미 코드 불일치 위험.
|
|
- **ca-tmpl과의 차이:**
|
|
- ca-tmpl은 **client-supplied key + body fingerprint mismatch 검출** 모델 (Stripe 계열).
|
|
- Powertools는 **server-derived key (= body hash)** 모델로 자동성은 높지만 "다른 직렬화 = 다른 요청" 위험.
|
|
- in-flight: Powertools 즉시 error vs ca-tmpl 200ms wait → ca-tmpl이 retry 친화적.
|
|
- TTL: Powertools 1h default vs ca-tmpl 24h → ca-tmpl이 더 긴 보존.
|
|
- **결론: ca-tmpl은 client intent (명시적 key)를 신뢰하는 모델, Powertools는 server가 intent를 추론하는 모델. 결제/상태 변경 도메인에선 ca-tmpl 쪽이 안전.**
|
|
|
|
## Related / 관련
|
|
|
|
- 같은 주제 다른 official-doc:
|
|
- [[raw/official-docs/idempotency-square-api]] — body 필드 방식 (header 아님)
|
|
- [[raw/official-docs/idempotency-no-api-level-github-rest]] — server dedup 부재 모델
|
|
- canonical contract 섹션:
|
|
- [[raw/project-notes/ca-skeleton-operational-contract]] §13. API Contract Surface (Idempotency-Key)
|
|
- [[raw/project-notes/ca-skeleton-operational-contract]] §18. Control Plane Contract (Rate Limit/Idempotency)
|
|
- 대안 그룹: **Topic 5 — Idempotency** (대안 5종 + 보조 1종: triple scope / Stripe pair / URL-based / content-hash / no-dedup / + DB vs Redis 저장소)
|
|
- 본 source의 위치: **대안 3: Content-hash (Powertools)**
|