17. 분산 락 lease 만료와 fencing token 부재 (C#)

난이도 상 해설 보기 →

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

결함 코드 · C#
// 시나리오: 분산 게임 서버 — 던전 인스턴스 상태를 한 워커만 갱신하도록 분산 락 사용
//
// 던전 인스턴스의 권위 있는 상태(보스 HP, 페이즈 등)는 동시에 한 워커 노드만
// 갱신해야 한다. 이를 위해 분산 락(예: Redis)에 TTL(lease)을 걸어 소유권을 얻는다.
// 락은 만료 시각(lease)이 지나면 자동 해제되어 다른 노드가 획득할 수 있다.
//
// 요구사항:
//  - 어떤 순간에도 인스턴스 상태를 갱신하는 노드는 하나뿐이어야 한다.
//  - 락을 잡은 노드가 GC 정지·네트워크 지연 등으로 오래 멈춰 lease 가 만료되면,
//    그 노드는 더 이상 유효한 소유자가 아니다.
//
// 아래 워커 처리 루프를 검토하라.

using System.Threading.Tasks;

public interface IDistributedLock
{
    // 성공 시 true. ttlMs 후 자동 만료.
    Task<bool> TryAcquire(string key, int ttlMs);
    Task Release(string key);
}

public interface IStateStore
{
    Task Write(string key, byte[] state);          // 인스턴스 상태 저장
    Task<byte[]> Read(string key);
}

public sealed class DungeonWorker
{
    private readonly IDistributedLock _lock;
    private readonly IStateStore _store;

    public DungeonWorker(IDistributedLock l, IStateStore s) { _lock = l; _store = s; }

    public async Task ProcessTick(string instanceId)
    {
        string lockKey = $"lock:dungeon:{instanceId}";
        if (!await _lock.TryAcquire(lockKey, ttlMs: 5000))    // (A) 5초 lease
            return;                                            // 다른 노드가 소유

        try
        {
            byte[] state = await _store.Read(instanceId);      // (B) 현재 상태 로드
            byte[] next = Simulate(state);                     // (C) 무거운 시뮬레이션(가변 시간)
            await _store.Write(instanceId, next);              // (D) 갱신 저장
        }
        finally
        {
            await _lock.Release(lockKey);                      // (E)
        }
    }

    private static byte[] Simulate(byte[] state) => state; // 자리표시자
}
내 리뷰 · C#
내 답안 · 자동 저장

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