2. 장애 후 재기동 시 배치 작업의 중복 처리/이중 실행 방지

난이도 중 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 장애 후 재기동 시 배치 작업의 중복 처리/이중 실행 방지
// ----------------------------------------------------------------------------
// 시나리오 (서버-서버/분산 · 운영/배포):
//   - "보상 지급 배치"가 있다. 운영 보상/시즌 정산/우편 일괄 지급처럼 대량의 작업을
//     주기적으로 처리한다. 각 작업(RewardJob)은 한 플레이어에게 골드를 지급한다.
//   - 이 배치는 (1) 스케줄러 틱마다 호출되고, (2) 서버가 죽었다가 재기동되면 미처리분을
//     이어서 처리하기 위해 다시 호출되며, (3) 무중단 운영을 위해 여러 워커 인스턴스가
//     동시에 돌 수 있다(같은 작업 목록을 공유).
//
// 요구사항:
//   - 각 RewardJob 은 정확히 "한 번만" 지급되어야 한다(at-most-once 효과).
//   - 어느 워커가 처리하든, 중간에 죽었다 재기동하든, 같은 작업이 두 번 지급되면 안 된다.
//   - 여러 워커가 같은 목록을 동시에 돌아도 한 작업을 두 워커가 같이 집으면 안 된다.
//
// 과제:
//   이 배치 러너의 잠재적 문제를 모두 찾고, (1) 동시 다중 워커, (2) 지급 직후 재기동 시
//   어떻게 이중 지급이 발생하는지 설명하고, 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System.Collections.Generic;

public class RewardJob
{
    public long JobId;
    public long PlayerId;
    public int  Gold;
    public bool Processed;
}

public class Wallet
{
    private readonly Dictionary<long, long> _gold = new();

    public void AddGold(long playerId, int amount)
    {
        _gold.TryGetValue(playerId, out var g);
        _gold[playerId] = g + amount;
    }
}

public class RewardBatchRunner
{
    private readonly List<RewardJob> _jobs;   // 공유 작업 목록(DB 테이블 대용)
    private readonly Wallet _wallet;

    public RewardBatchRunner(List<RewardJob> jobs, Wallet wallet)
    {
        _jobs = jobs;
        _wallet = wallet;
    }

    // 스케줄러 틱/재기동/여러 워커에서 호출될 수 있다
    public void RunPending()
    {
        foreach (var job in _jobs)            // (A)
        {
            if (job.Processed) continue;       // (B)
            _wallet.AddGold(job.PlayerId, job.Gold);   // (C)
            job.Processed = true;              // (D)
        }
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.