기대 멤버 집합의 완전성 검증과 원자 upsert
묶음 결과는 행 하나가 아니라 같은 batch key에 속한 기대 멤버 전체로 판정해야 합니다. 일부 행만 존재하는 상태를 완료로 오인하지 않는 읽기·쓰기 계약을 설명합니다.
묶음 생성 결과는 행 하나가 아니라 같은 batch_key에 속한 기대 member_code 집합 전체가 제품 결과입니다. 멤버 하나가 존재한다고 묶음 전체가 준비된 것은 아닙니다.
읽기와 쓰기의 같은 판정
조회는 GROUP BY batch_key 뒤 멤버 집합을 비교하고, 기대 집합과 같을 때만 생성 단위를 skip합니다. 부분 행은 다음 생성 라운드가 복구할 수 있도록 미완료로 남깁니다. 생성기는 중복·미지원 코드·잘못된 코드 이름·개수 부족을 DB 앞에서 거절합니다.
한 묶음, 한 transaction
| 판정 | 저장 동작 | 재시도 |
|---|---|---|
| 기대 멤버 전체 | 한 transaction으로 upsert | 불필요 |
| 멤버 일부 누락·중복 | 저장하지 않음 | 전체 묶음 재생성 |
| DB 오류 | rollback | 같은 묶음 재시도 |
검증된 기대 개수의 행은 executemany와 한 번의 commit으로 저장합니다. 한 행에서 오류가 나면 rollback하고 count를 0으로 보고합니다. 이렇게 하면 UI가 일부 성공을 전체 성공으로 오인하지 않고, scheduler가 재시도할 범위를 유지합니다.
이 원칙은 LLM 출력뿐 아니라 수동 Admin 생성과 자동 scheduler에도 적용해야 한다. 충돌 정책이 마지막 쓰기 우선이어도 완전하지 않은 묶음을 성공으로 만드는 것과는 별개의 문제다.
관련 강좌: 부분 실패·복구·플랫폼 경계를 교차 서비스 계약으로 닫기
검증할 때는 저장 전후의 기대 멤버 집합이 정확히 같은지, 오류 주입 뒤 행 수가 이전 상태로 유지되는지 함께 확인합니다.
data 카테고리의 다른 글
카테고리 전체 보기 →관련 글
검색을 ILIKE·pg_trgm·마이그레이션으로 최적화하기
콘텐츠 검색은 제목·설명·slug·lesson 본문에서 ILIKE '%검색어%'를 사용한다. 검색어를 escape하고 길이를 제한하는 것은 안전성 계약이고, wildcard 앞뒤 때문에 일반 B-tree 인덱스는 이 쿼리를 충분히 돕지 못한다.
통합 테스트의 마이그레이션 replay를 fail-closed로 만들기
통합 테스트가 스키마를 만들지 못했는데도 entity 테스트를 계속하면 실패가 지연되어 원인을 잃는다. 마이그레이션 디렉터리 누락, SQL 파일 0개, 파일 읽기 실패, 개별 SQL 오류는 모두 테스트 bootstrap 실패다.
콘텐츠 초기화 동시 실행을 막는 PostgreSQL advisory lock
콘텐츠 DB 초기화는 테이블 생성·스키마 보정·정적 시드·notes/courses 업서를 순서대로 묶습니다. 운영자가 버튼을 두 번 누르거나 console replica가 겹치면, 각 단계가 멱등이어도 두 파이프라인이 중간 상태를 서로 읽을 수 있습니다.
감사로그 — logAdminAction 패턴
관리자 기능을 갖춘 백엔드에서 "누가 · 언제 · 무엇을 · 왜" 의 네 축을 기록하는 감사로그 (audit log) 는 단순한 관행 이상입니다. 개인정보보호법 · GDPR 같은 규정 준수, 사고 조사, 권한 오남용 방지의 실질 수단.