Files

3.5 KiB

title, category, error_codes, severity, owner, last_updated, status
title category error_codes severity owner last_updated status
Runbook — async executor rejected TRANSIENT_DEPENDENCY
JOB_EXECUTOR_REJECTED
P1 oncall 2026-06-13 stub

Runbook: async executor rejected (runbook://job/executor-rejected)

1. Trigger

이 runbook은 다음 alert에서 발동됩니다.

  • alert name: executor_rejected
  • alert payload 필수 field: error.code=JOB_EXECUTOR_REJECTED, executor_name, policy, runbook_link
  • 임계: executor.rejected.total > 0 for 1m (p1) — bounded pool이 saturation으로 task를 거부
  • 보조 신호: executor.saturation gauge > queue capacity의 80% for 5m (p2)

2. First Response (5분 이내)

Step 1 — 확인

  1. ERROR log에서 JOB_EXECUTOR_REJECTED 라인 확인: executor_name, policy=AbortPolicy, queue_size 추출
  2. executor.saturation 패널에서 큐 점유율 추이 확인 — 일시적 burst인지 지속 saturation인지 판별
  3. 동시 유입 원인 파악: 신규 배포 / 트래픽 spike / 다운스트림 지연으로 worker가 장기 점유되는지

Step 2 — 임시 격리

  • AbortPolicy 거부는 호출부에 RejectedExecutionException으로 surface됨 — fire-and-forget @Async 호출이면 호출부의 async-exception 처리(log/metric)로 흡수됐는지 확인
  • 지속 saturation이면 유입 측(트래픽/스케줄러 빈도)을 우선 감속

3. Diagnosis

  • log query: {service="app"} | error.code="JOB_EXECUTOR_REJECTED" | stats count by executor_name
  • metric panel: executor.saturation{executor_name}, executor.rejected.total{executor_name, policy}
  • 가능한 원인 우선순위:
    • 다운스트림 의존성 지연 → worker가 반납되지 않아 큐 포화 (가장 흔함)
    • 트래픽 spike → 정상 부하 한계 초과
    • pool 과소 설정 (APP_ASYNC_EXECUTOR_*)
    • non-idempotent 작업이 retry로 누적

4. Mitigation

  • 단기: 유입 감속(상위 rate-limit / 스케줄러 interval 확대) 또는 다운스트림 의존성 회복
  • pool 재조정(restart-only): APP_ASYNC_EXECUTOR_CORE_SIZE / APP_ASYNC_EXECUTOR_MAX_SIZE / APP_ASYNC_EXECUTOR_QUEUE_CAPACITY — ⚠ queue를 무한정 키우지 말 것(unbounded 금지, D7). 부하테스트로 수치 검증 후 변경
  • CallerRunsPolicy로의 전환은 use-case 차원의 명시적 결정 필요(request thread latency 침식 — TPE-JDK21-C6)

5. Escalation

  • 다운스트림 의존성 장애가 근본 원인이면 해당 의존성 오너에게 escalate
  • pool 재조정으로도 saturation이 지속되면 용량 계획(capacity planning) 오너에게 page

6. Recovery / Verification

  • 회복 확인: executor.rejected.total 증가 멈춤, executor.saturation < 80% 정상화
  • 거부된 작업의 재처리 경로(멱등 retry / 다음 스케줄 cycle) 정상 동작 확인
  • error-codes.yaml rows: JOB_EXECUTOR_REJECTED (TRANSIENT_DEPENDENCY, 503, retryable=true, retry_after 5s)
  • metrics.yaml: executor.rejected.total{executor_name, policy}, executor.saturation{executor_name}
  • 코드: app-bootstrap async/AsyncExecutorConfig(bounded executor), async/LoggingAbortPolicy(reject log+metric), async/BackgroundJobMetrics
  • env: APP_ASYNC_EXECUTOR_CORE_SIZE / APP_ASYNC_EXECUTOR_MAX_SIZE / APP_ASYNC_EXECUTOR_QUEUE_CAPACITY
  • 관련 runbook: job-timeout, job-dead-letter
  • 관련 branch: feature-background-job-async-contract (D7 saturation policy)

Stub 상태 안내: 이 runbook은 skeleton 단계의 stub. 실제 부하 프로파일·alert 채널·pool 수치 확정 시 보강 필요.