Skip to content

cluster: 채널 소유 기반 게이트웨이 인그레스로 leader forwarding 계층 대체 (첨부 멀티노드 미지원·채널 failover 포함) #5713

Description

@itismyfield

배경

AgentDesk 멀티노드는 "봇 토큰당 Discord 게이트웨이는 하나"를 전제로 설계됐다. 게이트웨이 리스(discord_gateway_lock_id, PG advisory lock)를 잡은 leader만 웹소켓을 열고, 다른 노드 소유 세션으로 가는 메시지는 leader가 intake_outbox에 넣어 forwarding한다(cluster.intake_routing.mode: enforce, 운영 켜짐). 이 forwarding 계층 위에 trusted origin 검증, outbox 재시도/claim 회수, 첨부 이식성 판정, 세션 소유자 해석이 쌓여 있다.

사용자 관점 결함(2026-09-05 확인):

제안: 채널 소유 기반 게이트웨이 인그레스

Discord 게이트웨이는 채널 단위 구독이 없다. 봇 토큰으로 접속한 모든 세션이 모든 이벤트를 받는다. 그러므로 각 노드가 게이트웨이를 직접 열고, 자기가 소유하지 않은 채널 이벤트는 인그레스에서 버린다. forwarding 계층은 제거 대상이 된다.

  • 소유 정본: PG 채널 → 소유 노드 + 리스 만료 + epoch 테이블. 소유 노드가 heartbeat로 갱신.
  • DM: 길드가 없으므로 사용자 → 담당 노드 매핑을 별도로 둔다.
  • 슬래시 명령·컴포넌트 인터랙션: 3초 내 정확히 한 노드가 ack해야 한다. 소유 판정이 어긋나면 이중 응답 또는 무응답이므로 소유 테이블 조회를 인그레스 첫 단계에 둔다.
  • 첨부: 소유 노드가 Discord CDN에서 직접 받으므로 이식성 문제가 사라진다. 전환 전 단기 수리가 필요하면 forwarding 시 로컬 경로 대신 CDN URL(서명 포함, 약 24시간 유효) 또는 바이트를 넘기는 것으로 한다. 이 단기 수리는 본 이슈 범위에 포함하되 별도 PR로 먼저 착지 가능.
  • 싱글턴 잡(policy tick, github-sync)은 지금처럼 leader 리스를 유지한다. 게이트웨이 리스만 폐지 대상.

Failover (채널 소유 노드가 떨어졌을 때)

가능한 것: 받아서 답하기. 소유 노드 heartbeat가 끊기면 리스 만료 뒤 다른 노드가 채널을 가져간다. 지금의 봇 단위 failover(docs/multimachine-failover.md)를 채널 단위로 내리는 것과 같다.

불가능한 것: 하던 작업 이어가기. tmux, Claude/Codex TUI 프로세스, 워크트리, ~/.claude/projects/ 대화 파일이 전부 소유 노드 로컬이다. 인수한 노드는 새 세션을 열어 응답할 수 있을 뿐이다. 세션 연속성은 별개 이슈로 다룬다.

반드시 같이 설계할 것:

  1. 원 소유 노드 복귀 시 split-brain. 리스 epoch로 낮은 세대의 응답을 차단하고, 되찾기 정책(강제 회수 vs 인수 노드가 놓을 때까지 대기)을 정한다.
  2. 다운 구간 메시지. Discord는 새 웹소켓 세션에 지난 이벤트를 재전송하지 않으므로, 마지막 처리 메시지 id 이후를 REST로 catch-up 한다. leader의 기존 CATCH-UP 로직을 채널 단위로 이관.

트레이드오프

현재(leader forwarding) 제안(채널 소유 인그레스)
봇 토큰 leader만 모든 노드
게이트웨이 트래픽 노드 수 × (2대 규모에서 무시 가능)
첨부 비이식, 차단 소유 노드가 직접 다운로드
실패 지점 forwarding 경로 전체 소유 테이블 정합성
인터랙션 ack leader 단일 소유 판정 정확성에 의존
코드 outbox/claim/trusted origin/portability 유지 그 계층 제거, 소유 리스 + catch-up 추가

착수 조건

완료 정의

  • 첨부 단기 수리: 다른 노드 소유 세션으로 이미지·파일 첨부가 전달되어 에이전트가 읽는다 (mac-mini 복구 후 실측)
  • 설계 문서 리뷰 통과 (위 failover·split-brain·catch-up·인터랙션 ack 4항목 각각 결정 기록)
  • 구현: leader 게이트웨이 리스와 intake_outbox forwarding 경로 제거, 채널 소유 리스 인그레스로 대체, 2노드 스모크(docs/agent-maintenance/multinode-two-node-smoke.md 갱신)
  • failover 실측: 소유 노드 중단 → 리스 만료 → 다른 노드가 새 세션으로 응답 → 원 노드 복귀 시 이중 응답 0건

관련

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions