Skip to content

만료된 제재가 풀리지 않는다: 배치가 예외를 삼켜 진단 불가능한 무한 재시도가 된다 #264

Description

@kcrmin

AWS Development 관측

운영자 화면에서 만료 시각이 임박한 SUSPENSION 제재를 적용한 뒤(INT05 구간), 제재가 만료됐는데
상태가 ACTIVE 로 3시간 넘게 남았습니다.

identity.account_sanctions
  id           52b9effa-69eb-4281-8bd8-0c842fdc8858
  account_id   91687695-21be-4fd7-8855-6f0552395cc0
  sanction_type SUSPENSION      status ACTIVE
  applied_at   2026-08-09 04:59:19Z
  expires_at   2026-08-09 05:00:00Z     ← 만료

operations.audit_events 에는 그 뒤로 이렇게 남았습니다.

target_domain=SANCTION  action_type=BATCH_RETRY  reason_code=UNCLASSIFIED_EXECUTION_FAILURE
actor_type=SYSTEM  target_id=664a4431-7624-3737-aebc-719c7e1bda8a
180 건, 05:00:36Z ~ 08:14:45Z, 대상 1개, 약 60초 주기

배치 로그는 이것만 남깁니다.

DeadlineBatchRunner : Deadline batch completed: runId=3db4fc65-…, claimed=1, completed=0,
                      alreadyCompleted=0, failures=2

예외는 어디에도 없습니다. 3시간 동안 180번 실패했는데 무엇이 실패했는지 알 수 있는 기록이 없습니다.
루프가 멈춘 이유도 수정이 아니라 릴리스 31302328826 이 core 인스턴스를 교체해서 profiles: [manual]
컨테이너가 사라진 것입니다.

원인

DeadlineBatchOrchestrator.java:145-149

try {
    result = Objects.requireNonNull(port.execute(item, command.runId(), command.correlationId()), "item result");
} catch (RuntimeException failure) {
    result = ItemResult.retryable("UNCLASSIFIED_EXECUTION_FAILURE");
}

failure로그도 없이 버려집니다. 이 클래스에는 로거가 아예 없습니다(stableCategoryFailure
예외를 문자열로 접기만 합니다). 그래서:

  1. 진단이 불가능합니다. 감사 기록은 "실패했다" 만 말하고 "무엇이" 를 말하지 않습니다. A90 이 묻는
    "감사 계약이 실제로 쓸 만한가" 에 대한 답이 여기서 아니오입니다.
  2. 결정적 실패가 무한 재시도됩니다. 매번 retryable 로 분류되므로 같은 예외가 60초마다 되돌아옵니다.
    180회 시점에도 죽은 편지함으로 가지 않았습니다. runtime-policy.jsonattempt.maxAttempts=3
    이 이 경로에 적용되지 않는 것으로 보입니다.
  3. 사용자에게 보이는 결과: 만료된 정지가 풀리지 않습니다. 계정이 계약보다 오래 잠긴 상태로 남습니다.

요구하는 수정

  • 예외를 보존한다. 항목 식별자(category·itemId·idempotencyKey·attemptNumber)와 runId·correlationId
    과 함께 ERROR 로 스택을 남긴다. 감사의 reason_code 어휘는 안정적으로 유지한다 — 예외 메시지를
    감사 행에 넣어 어휘를 오염시키지 않는다.
  • 같은 항목의 결정적 실패가 무한 재시도되지 않도록 시도 한도를 이 경로에 적용하거나, 한도 초과를
    죽은 편지함으로 보낸다. 어느 쪽인지 명시적으로 결정하고 근거를 남긴다.
  • 회귀: port.execute 가 던질 때 (a) 원인이 기록되고 (b) 한도 초과 시 RETRYABLE_FAILURE 가 아닌
    종단 처분이 되는 것을 단정한다.

부수 발견 — 감사 어휘 분화 (A90 본체)

같은 조회에서 나온 것을 함께 남깁니다. db/reconciliation/audit-vocabulary.sql 를 배포된 DB 에
처음 돌린 결과입니다.

관측 내용
target_domain 이 같은 개념에 둘 ACCOUNT_SANCTION(APPLY/LIFT) 과 SANCTION(BATCH_RETRY). 한쪽으로 필터하는 감사 검토는 나머지를 놓칩니다
action_type 작명이 섞임 맨 동사(APPLY, LIFT) vs 도메인 접두(OPERATOR_RBAC_READ_SELF, BATCH_RUN_COMPLETED)
reason_code 의 의미가 섞임 APPLY→SANCTION_APPLIED(행위 반복) vs BATCH_RETRY→UNCLASSIFIED_EXECUTION_FAILURE(실제 사유)

표본: 435건, action_type 8종, target_domain 5종, 2026-08-08~09. 작지만 분화는 명확합니다.
action_type·target_domain 이 열 곳 이상의 어댑터에서 각자 채워지고 한 곳에 정의되지 않는 것이
근본 원인입니다.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions