11 KiB
title, source_type, url, archive_url, status, confidence, tags, related_projects, related_branches, created, last_reviewed
| title | source_type | url | archive_url | status | confidence | tags | related_projects | related_branches | created | last_reviewed | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 우아한형제들 — 트랜잭션 커밋 이후 캐시 무효화 (after-commit invalidation 사례) | company-tech-blog | https://techblog.woowahan.com/2667/ | raw | medium |
|
|
|
2026-05-22 | 2026-05-27 |
우아한형제들 — 트랜잭션 커밋 이후 캐시 무효화 사례
Layer:
raw/company-tech-blogs/— 우아한형제들 기술블로그 사례 발췌 (요지 발췌, 한국어). ca-tmpl 의 "cache invalidation = after-commit only" 결정의 사례 근거 (공식 best-practice 가 아닌 case-study 취급).
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-cache-consistency-contract | "tx 내부 cache mutation forbidden + afterCommit invalidation 강제" 결정의 한국 도메인 사례 근거. invalidation 실패 → 별도 처리 (observable failure, 재시도/비동기 큐) 요구의 사례 출처 |
| raw/branch-notes/feature-transaction-concurrency-contract | TransactionSynchronizationManager.registerSynchronization 의 afterCommit 후크 활용 패턴의 사례 — port adapter 가 트랜잭션 lifecycle 에 hook 하는 구현 옵션 |
컨텍스트
ca-tmpl 결정 "cache invalidation = after-commit only" 의 사례 근거. Spring TransactionSynchronizationManager.registerSynchronization 을 실제 도메인에서 쓰는 한국 기업 사례.
출처 / Source
- 원본 URL: https://techblog.woowahan.com/2667/
- 보조: 우아한형제들 기술블로그의 다른 캐시 글 묶음 (Redis, 동시성)
- 참고 검색어: "우아한형제들 캐시 무효화 트랜잭션", "woowahan transactionsynchronization registerSynchronization"
- 아카이브 URL: (미수집)
- 저자 / 조직: 우아한형제들 (Woowahan Brothers / Woowa Bros.) — 기술블로그
- 발행일: rolling docs (페이지 자체에 명시 없음)
- 마지막 확인일: 2026-05-27
- 재검증 한계: WebFetch 차단 — 본 인용은 user 수집본 (2026-05-22) 보존, verbatim 재확인 보류. 본 자료의 인용은 "요지 발췌" 로 명시되어 있어 원문 일치도 검증 시 paraphrase 가능성 있음. ca-tmpl 의
verified승급 전 원문 재확인 의무.
핵심 인용 / Key quotes (verbatim)
[§요지 — 글 본문 요약] needs-confirmation (요지 발췌, paraphrase 가능성): "캐시 무효화를 트랜잭션 내부에서 호출하면, 커밋이 롤백된 경우에도 캐시는 이미 invalidate 된다. 다른 트랜잭션이 그 사이 cache miss → DB 조회로 stale 값을 다시 채우는 race 가 발생했다."
[§해결책] needs-confirmation (요지 발췌): "해결책으로
TransactionSynchronizationManager.registerSynchronization을 이용해afterCommit시점에만 캐시 무효화를 수행하도록 변경했다. 롤백 시에는 캐시를 건드리지 않는다."
[§한계] needs-confirmation (요지 발췌): "단,
afterCommit자체는 트랜잭션 외부이므로 무효화 실패는 별도 처리 (observable failure, 재시도 또는 비동기 큐 전송) 가 필요하다."
[§선언적 대안] needs-confirmation (요지 발췌): "Spring
@TransactionalEventListener(phase = AFTER_COMMIT)로 같은 효과를 더 선언적으로 얻을 수 있다."
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| WOOWA-CACHE-C1 | 사례: 트랜잭션 내부 cache invalidation 호출 시 rollback 발생하면 cache 만 invalidate 되고 DB 는 유지 → 동시 다른 tx 의 cache miss → DB 조회 → stale 값 재로딩 race 가 발생 | [§요지] needs-confirmation: "캐시 무효화를 트랜잭션 내부에서 호출하면, 커밋이 롤백된 경우에도 캐시는 이미 invalidate 된다. 다른 트랜잭션이 그 사이 cache miss → DB 조회로 stale 값을 다시 채우는 race 가 발생했다." | company-case-study |
우아한형제들 도메인의 특정 워크로드 (정확한 endpoint 범위는 글에 비명시) | 이 race 가 모든 cache + tx 환경에서 항상 발생한다는 일반 best-practice 보장은 아님 — 사례 1건 |
| WOOWA-CACHE-C2 | 사례 해결책: TransactionSynchronizationManager.registerSynchronization 의 afterCommit 후크로 cache invalidation 을 commit 이후로 지연 — rollback 시에는 cache 미터치 |
[§해결책] needs-confirmation: "해결책으로 TransactionSynchronizationManager.registerSynchronization 을 이용해 afterCommit 시점에만 캐시 무효화를 수행하도록 변경했다. 롤백 시에는 캐시를 건드리지 않는다." |
company-case-study |
Spring TransactionSynchronizationManager 사용 환경 |
afterCommit 후크 사용이 모든 도메인에서 표준 패턴이라는 보장은 아님. 단, Spring 공식 javadoc 에 메커니즘은 명시 (별도 raw 필요) |
| WOOWA-CACHE-C3 | 사례 한계 인식: afterCommit 은 트랜잭션 외부이므로 cache invalidation 실패 시 트랜잭션이 rollback 되지 않음 → observable failure 노출 + 재시도 / 비동기 큐 전송 등 보상 로직 별도 필요 |
[§한계] needs-confirmation: "단, afterCommit 자체는 트랜잭션 외부이므로 무효화 실패는 별도 처리 (observable failure, 재시도 또는 비동기 큐 전송) 가 필요하다." |
company-case-study |
afterCommit hook 으로 cache invalidation 위임한 모든 환경 |
본 사례가 제시한 specific 보상 메커니즘 (재시도 vs 비동기 큐) 의 선택 기준은 글에 명시 없음 |
| WOOWA-CACHE-C4 | 선언적 대안 언급: 동일 효과를 Spring @TransactionalEventListener(phase = AFTER_COMMIT) 로 얻을 수 있다는 언급 |
[§선언적 대안] needs-confirmation: "Spring @TransactionalEventListener(phase = AFTER_COMMIT) 로 같은 효과를 더 선언적으로 얻을 수 있다." |
company-case-study |
Spring 4.2+ 환경 | @TransactionalEventListener 가 registerSynchronization 보다 모든 면에서 우월하다는 평가는 글에 명시 없음 — listener 미등록 환경 silent drop 위험은 별도 (Spring official 문서 필요) |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것 (재검증 한계 + 사례 한정):
WOOWA-CACHE-C1~C4: 우아한형제들이 겪은 특정 race condition +TransactionSynchronizationManager.afterCommit채택 + 외부 처리 필요성 인식 +@TransactionalEventListener대안 언급
- 이 자료가 증명하지 않는 것 (company-tech-blog 일반 한계 + 본 사례 한정):
- 한국 기업 표준 / Spring 공식 권장 — 본 자료는 사례 1건 (CLAUDE.md §5: "공식 best-practice 로 취급 금지")
- 모든 cache + tx 조합에서
afterCommit패턴이 최적이라는 일반화 — 사례의 워크로드 특성 (read-heavy / write 빈도) 미명시 TransactionSynchronizationManagervs@TransactionalEventListener의 선택 기준 — 글이 두 옵션을 언급하나 비교 분석 부재- cache invalidation 실패의 정확한 모니터링 / alert 메커니즘 — "observable failure" 만 언급, 구현 디테일 부재
- 본 자료 단독으로
afterCommit패턴을 "official best practice" 로 격상 불가 → Spring 공식 문서 (별도 raw) 와 corroborate 필요 (다른 raw 의 official-vendor-doc strength claim 과 결합 시에만 일반화 가능)
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- 재검증 한계로 인한 SSOT 확인 의무: ca-tmpl 의
verified/published-ready승급 전, 원문 직접 재확인하여 paraphrase vs verbatim 명확화 - ca-tmpl 의
CACHE/INVALIDATION_FAILUREerror code 분류가 본 사례의 "observable failure" 시맨틱과 일치하는지 (재시도 정책, alert 임계값 등) @TransactionalEventListener채택 시 listener bean 등록 누락에 대한 build-time/test-time 검출 가드 (silent drop 방지)
- 재검증 한계로 인한 SSOT 확인 의무: ca-tmpl 의
메모 / Notes (내 프로젝트 해석)
본 섹션은 자료 직접 인용 아님. ca-tmpl 결정 컨텍스트 해석.
- ca-tmpl 결정과의 정합성:
- "tx 내부 또는 tx 미참여 상태에서의 cache mutation 은 forbidden" ← 같은 문제의식 (WOOWA-CACHE-C1).
- "invalidation 실패가 조용히 무시되면 실패" 테스트 ← 우아한형제들 사례의 후속 문제 (afterCommit 외부 실패 처리, WOOWA-CACHE-C3).
- 두 가지 구현 옵션 (둘 다 본 사례에서 언급):
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { afterCommit() { … } })— adapter 에서 직접 등록.- domain event 발행 +
@TransactionalEventListener(phase = AFTER_COMMIT)— 더 선언적, 그러나 listener 가 등록 안 된 환경에서 silent drop 위험.
- ca-tmpl test 계약 매핑:
- "tx rollback 시 cache 에 stale write 가 남으면 실패" ← afterCommit 강제로 자동 만족.
- "invalidation 실패가 조용히 무시되면 실패" ← afterCommit 안에서 발생한
RedisConnectionException을 swallow 하면 실패. ca-tmpl 은 별도 error code (CACHE/INVALIDATION_FAILURE) 로 분류 권장.
- 취급 주의: 회사 기술블로그는 "공식 best-practice 가 아님" (CLAUDE.md §5). 패턴 자체는 Spring 공식 문서가 권장 (
@TransactionalEventListenerJavadoc — 별도 official-vendor-doc 인용 필요). - 시사점: ca-tmpl 의 결정은 우아한형제들 사례 + Spring 공식 메커니즘의 교집합. 임의 결정 아님 — 단, 본 raw 단독으로는 사례 근거이며 official-vendor-doc raw 와 corroborate 시에만 일반화 가능.
Related / 관련
- 같은 주제 다른 raw:
- raw/official-docs/spring-transactional-event-listener (Spring
@TransactionalEventListener공식 정의 + phase 시맨틱 → 본 사례의 "더 선언적" 대안의 official-vendor-doc 근거) - raw/official-docs/cache-redisson-rlock-vs-setnx (cache stampede 방지 도구 선택)
- raw/official-docs/spring-transactional-event-listener (Spring
- 적용 ca-tmpl branch-note:
- canonical contract 섹션:
- raw/project-notes/ca-skeleton-operational-contract (cache consistency 관련 섹션)
- 대안 그룹: Group G-C — Cache consistency (invalidation timing: a) inline in tx [forbidden] / b) afterCommit registerSynchronization [ca-tmpl] / c)
@TransactionalEventListenerAFTER_COMMIT / d) async outbox 로 위임) — 본 source 는 b 채택 사례 + c 대안 언급. - 인용한 wiki 요약: (미작성)