c24165b8bc
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게 [공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류. 문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인). - Topic_Programming → Domain_Programming (내부 구조 보존) - Topic_Graphic → Domain_Design - Topic_Business → Domain_Product - Topic_General → Domain_General - _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning), Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing) - 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서) - 빈 폴더 정리 (memory/procedures) - 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.3 KiB
5.3 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, created_at, updated_at, last_reinforced, review_reason, merge_history, tags, raw_sources, tech_stack, applied_in
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | created_at | updated_at | last_reinforced | review_reason | merge_history | tags | raw_sources | tech_stack | applied_in | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| idempotent-operations | 멱등성 연산 실전 (Idempotent Operations) | Coding | draft | idempotent-operations |
|
null | B | 0.9 | conceptual | 2026-05-09 | 2026-05-09 | 2026-05-09 |
|
|
|
멱등성 연산 실전
같은 요청이 N번 와도 부작용은 1번분만. 분산 시스템에서 "exactly-once" 는 불가능에 가깝고, "at-least-once + idempotent" 가 현실적 답이다.
📖 핵심 개념
멱등성(idempotent): f(f(x)) == f(x). 연산을 여러 번 적용해도 첫 번째 적용과 결과가 같음.
분산 환경의 모든 네트워크 호출은 재시도 가능성이 있다 (ACK 유실 / 타임아웃 / 클라이언트 retry). 따라서 다음을 항상 가정:
- 클라이언트는 같은 요청을 여러 번 보낼 수 있다
- 메시지 큐는 같은 메시지를 여러 번 전달할 수 있다 (at-least-once delivery)
- DB 트랜잭션은 commit 후 응답을 못 받고 재시도될 수 있다
해결: 연산 자체를 멱등하게 만들거나, 외부 idempotency key로 중복 감지.
💻 코드 패턴
1. HTTP 엔드포인트 — Idempotency-Key 헤더
// Express
app.post('/api/payments', async (req, res) => {
const key = req.header('Idempotency-Key');
if (!key) return res.status(400).json({ error: 'Idempotency-Key required' });
// 1) 같은 키의 이전 응답을 캐시에서 조회
const cached = await redis.get(`idem:${key}`);
if (cached) return res.json(JSON.parse(cached));
// 2) 진짜 결제 수행 (DB 트랜잭션 안에서 키 unique 보장)
try {
const payment = await db.transaction(async (tx) => {
await tx.idempotencyKeys.insert({ key, status: 'processing' }); // UNIQUE
const result = await chargePayment(req.body);
await tx.idempotencyKeys.update(key, { status: 'done', response: result });
return result;
});
await redis.setex(`idem:${key}`, 86400, JSON.stringify(payment));
res.json(payment);
} catch (e) {
if (isUniqueViolation(e)) {
// 이전 호출이 진행 중 — 클라이언트가 잠시 후 재시도하도록
return res.status(409).json({ error: 'In progress, retry later' });
}
throw e;
}
});
2. SQL — UPSERT 로 멱등 INSERT
-- 같은 user_id 가 여러 번 들어와도 한 행
INSERT INTO user_settings (user_id, theme)
VALUES ($1, $2)
ON CONFLICT (user_id) DO UPDATE SET theme = EXCLUDED.theme;
3. Message Queue Consumer — processed_id 테이블
async function handleMessage(msg: { id: string; payload: any }) {
const inserted = await db.processedMessages.insertIfAbsent({ id: msg.id }); // UNIQUE
if (!inserted) {
logger.info('Duplicate message ignored', { id: msg.id });
return; // 이미 처리됨
}
await actuallyProcess(msg.payload);
}
🤔 의사결정 기준
| HTTP 메서드 | 멱등성 기본값 | 강제 필요 |
|---|---|---|
| GET / HEAD / PUT / DELETE | 멱등 (RFC 9110) | 일반적으로 자연스러움 |
| POST | 비멱등 | 반드시 Idempotency-Key 도입 |
| 작업 종류 | 멱등화 전략 |
|---|---|
| 결제 / 외부 API 호출 | Idempotency-Key + 응답 캐시 |
| DB INSERT | UPSERT or UNIQUE 제약 |
| 메시지 큐 consumer | processed_id 테이블 |
| 파일 업로드 | content hash 기반 dedup |
| 카운터 증가 | 이건 멱등화 어려움 — sequence number / event sourcing 고려 |
❌ 안티패턴
- 클라이언트가 키를 안 보냈다고 그냥 처리: "키 없으면 실패" 가 안전. 키를 매번 새로 만드는 클라이언트는 매번 새 결제로 처리되어도 클라이언트 책임.
- 응답 캐시 TTL 너무 짧음: 24시간 권장. 그보다 짧으면 늦은 retry가 새 처리를 만듦.
- 카운터 증가를 "그냥 두 번 올리면 되지" 식으로 처리: at-least-once + ++counter 는 정확한 카운트 보장 못 함. 이벤트 소싱 또는 외부 dedup 필요.
- 트랜잭션 밖에서 키 체크: 키 체크 → 실 처리 사이에 race. 키 INSERT는 같은 트랜잭션 안에서.
- 에러 응답도 캐싱: 일시 오류(5xx)를 캐시하면 후속 retry가 모두 실패. 4xx만 캐싱, 5xx는 캐시 안 함.
🤖 LLM 활용 힌트
- LLM에게 외부 호출 코드 작성을 시킬 때 "at-least-once delivery 가정 + Idempotency-Key 패턴 적용" 명시.
- DB INSERT 코드: "같은 키로 N번 호출되어도 한 행만 남도록" 라고 요청 → UPSERT or UNIQUE.
- 메시지 핸들러 작성: "이 핸들러는 같은 메시지가 N번 들어와도 안전해야 함" 명시.
🧪 검증 상태
- verification_status:
conceptual - Stripe / AWS / Square 의 실제 결제 API 가 모두 Idempotency-Key 사용 → B급 출처.
- 적용 사례 발견 시
applied_in추가.