Skip to content

Story: 영구 삭제 배치 (7일 경과)

메타

항목
Story IDE-09-S-07
EpicE-09 미사용 상품 정리
상태ready-for-dev
우선순위P1
규모S
담당 개발자BE

사용자 스토리

As a 시스템,
I want 7일 경과한 삭제 상품을 영구 삭제하고 싶다,
So that DB 스토리지를 효율적으로 관리할 수 있다.


수락 기준 (Acceptance Criteria)

AC-01: 배치 실행

항목내용
Given매일 새벽 3시에
When영구 삭제 배치가 실행되면
Then7일 경과한 Soft Delete 상품이 Hard Delete 된다

AC-02: 배치 처리 방식

항목내용
Given대량 삭제 시
When배치 단위로 처리하면
ThenDB 락 최소화 (1,000건씩 처리)

AC-03: 실패 처리

항목내용
Given배치 실행 중 에러 발생 시
When3회 재시도 후 실패하면
Then알림 발송 + 로그 기록

태스크 분해

Task 1: 배치 작업 구현

  • [ ] 1.1: 7일 경과 상품 조회
    sql
    SELECT id FROM Product
    WHERE deleted_at IS NOT NULL
      AND deleted_at < DATE_SUB(NOW(), INTERVAL 7 DAY)
    LIMIT 1000;
  • [ ] 1.2: 배치 단위 Hard Delete (1,000건씩)
  • [ ] 1.3: 트랜잭션 처리

Task 2: 스케줄링

  • [ ] 2.1: 매일 새벽 3시 실행 (Cron)
  • [ ] 2.2: 중복 실행 방지 (Lock)

Task 3: 모니터링

  • [ ] 3.1: 배치 실행 로그
    • 시작 시간, 종료 시간, 삭제 건수
  • [ ] 3.2: 실패 시 Slack/이메일 알림
  • [ ] 3.3: 배치 실행 대시보드 (선택)

배치 스펙

실행 조건

항목
실행 시간매일 03:00 (KST)
대상deleted_at < NOW() - 7 DAY
배치 크기1,000건/트랜잭션
최대 실행 시간30분
재시도3회

배치 로직

typescript
async permanentDeleteBatch() {
  const BATCH_SIZE = 1000;
  const SEVEN_DAYS_AGO = subDays(new Date(), 7);

  let totalDeleted = 0;

  while (true) {
    // 1. 대상 조회
    const products = await this.productRepo.find({
      where: {
        deletedAt: LessThan(SEVEN_DAYS_AGO)
      },
      take: BATCH_SIZE
    });

    if (products.length === 0) break;

    // 2. 배치 삭제
    const ids = products.map(p => p.id);
    await this.productRepo.delete({ id: In(ids) });

    totalDeleted += products.length;

    // 3. 로그
    this.logger.info(`Batch deleted ${products.length} products`);

    // 4. 부하 분산
    await sleep(100);
  }

  return { totalDeleted };
}

모니터링

배치 로그 형식

json
{
  "job": "product_permanent_delete",
  "startedAt": "2026-01-20T03:00:00Z",
  "completedAt": "2026-01-20T03:05:23Z",
  "status": "success",
  "totalDeleted": 1532,
  "batchCount": 2,
  "duration": "5m 23s"
}

알림 조건

조건알림
성공없음 (로그만)
실패 (3회 재시도 후)Slack 알림
실행 시간 > 30분Slack 알림
삭제 건수 > 10,000정보성 Slack 알림

이벤트 로깅

이벤트파라미터
batch_permanent_delete_startedscheduled_time
batch_permanent_delete_completedtotal_deleted, duration
batch_permanent_delete_failederror_message, retry_count

생성일: 2026-01-20

장사왕 Product Team