3. 긴급 점검 종료의 드레이닝 부재 (순서·대기·플러시 누락)

난이도 최상 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 긴급 점검 공지 후 강제 종료까지의 드레이닝(graceful drain)
// ----------------------------------------------------------------------------
// 시나리오 (서버-서버/분산 · 운영/장애):
//   - 긴급 점검을 위해 게임 서버를 내려야 한다. 공지 후 짧은 유예를 두고 종료한다.
//   - 이 서버는 ① 처리 중인 요청(일부는 다른 존 서버로 RPC를 보내는 멀티스텝),
//     ② 비동기 영속화 큐(_persist: 더티 상태를 백그라운드로 DB 저장),
//     ③ 클러스터 등록(_cluster: 다른 서버들이 이 서버로 라우팅)을 가진다.
//
// 요구사항:
//   - 종료 시 진행 중이던 작업이 "반쯤"만 적용된 채 끊기면 안 된다(예: 존 이전에서
//     원본에서 제거됐는데 대상에 추가 안 됨).
//   - 영속화 큐에 쌓인 변경은 유실되면 안 된다(저장 후 종료).
//   - 종료 중/후에 다른 서버가 이 서버로 새 작업을 보내면 안 된다.
//
// 과제:
//   이 종료 절차의 잠재적 문제를 모두 찾고, 처리 중 요청과 _persist 큐, _cluster 라우팅에
//   무슨 일이 일어나는지 설명하고, 올바른 드레이닝 순서/수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.Collections.Generic;

public class GameServer
{
    private volatile bool _running = true;
    private readonly Listener     _listener;
    private readonly List<Session> _sessions;
    private readonly PersistQueue _persist;   // 비동기 영속화 큐
    private readonly Cluster      _cluster;    // 서버-서버 라우팅 등록

    public GameServer(Listener l, List<Session> s, PersistQueue p, Cluster c)
    { _listener = l; _sessions = s; _persist = p; _cluster = c; }

    // 긴급 점검: 공지 후 종료를 호출
    public void Shutdown()
    {
        _running = false;                 // (A) 처리 중단 플래그
        _listener.Close();                // (B) 새 연결 차단

        foreach (var s in _sessions)      // (C) 모든 세션 즉시 끊기
            s.CloseSocket();

        Environment.Exit(0);              // (D) 프로세스 종료
    }

    // 요청 처리(워커 여러 개). 일부는 다른 존 서버로 RPC를 보내는 멀티스텝.
    public void HandleRequest(Session s, Request req)
    {
        if (!_running) return;
        // step1: 로컬 상태 변경 → _persist.Enqueue(dirty)
        // step2: 다른 존 서버로 RPC(존 이전 등) → 응답 대기
        // step3: 로컬 커밋 / 세션에 결과 전송
        // (멀티스텝 중간에 (C)/(D)가 끼어들 수 있다)
    }
}

public class Listener     { public void Close() { } }
public class Session      { public void CloseSocket() { } }
public class PersistQueue { public void Enqueue(object dirty) { } /* 백그라운드 saver 가 비움 */ }
public class Cluster      { public void Register() { } public void Deregister() { } }
public class Request      { }
내 리뷰 · C#
내 답안 · 자동 저장

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