← posts/b.log()

blog92@web:~$ cat posts/websocket-08-message-design.md

NETWORK1 min read

WebSocket 완전 정복 8편 — 메시지 설계: 봉투 형식, correlation id, 그리고 seq

WebSocket이 메시지의 의미를 정해 주지 않으므로 직접 설계해야 하는 애플리케이션 프로토콜을 다룹니다. 타입 유니온으로 표현한 봉투 형식, 요청-응답을 잇는 correlation id, 재연결 복구의 토대가 되는 seq, 버전 관리 원칙과 RPC 클라이언트 구현을 담았습니다.

WebSocket 완전 정복 · 2부. 중급: 프로토콜 내부와 설계 패턴 · 16편 중 8편

이전 편: 7편 — 제어 프레임

프레임과 제어 프레임까지가 프로토콜이 정해 주는 전부입니다. 메시지 안에 무엇을 어떤 형식으로 담을지는 WebSocket이 정하지 않으므로, 이번 편은 그 애플리케이션 프로토콜을 직접 설계합니다 — 봉투 형식, 요청과 응답을 잇는 correlation id, 재연결 복구의 토대가 되는 seq입니다.

봉투(envelope) 형식

WebSocket은 메시지의 의미를 정하지 않으므로 애플리케이션 프로토콜을 직접 설계합니다.

ts
type Envelope =
  | { type: "subscribe"; id: string; channel: string }
  | { type: "unsubscribe"; id: string; channel: string }
  | { type: "publish"; id: string; channel: string; data: unknown }
  | { type: "ack"; id: string; ok: boolean; error?: string }
  | { type: "event"; channel: string; seq: number; data: unknown };

다섯 가지 원칙

  • type으로 분기하고, 모르는 타입은 무시하지 말고 오류 응답.
  • 요청-응답에는 id(correlation id). 클라이언트가 만들고 서버가 ack에 실어 보냄.
  • 서버 이벤트에는 채널별 seq. 재연결 후 "마지막 seq 이후"를 요청할 수 있고 누락·중복 감지 가능.
  • 처음부터 버전 관리(서브프로토콜 chat.v1 또는 v 필드). 배포 중엔 구·신버전이 반드시 섞임.
  • 성능이 중요하면 MessagePack/Protobuf 바이너리. 단, 병목 확인 후에.

요청-응답을 잇는 RPC 클라이언트

ts
class RpcClient {
  private pending = new Map<string, (msg: any) => void>();
  constructor(private ws: WebSocket) {
    ws.addEventListener("message", (e) => {
      const msg = JSON.parse(e.data);
      if (msg.type === "ack") {
        this.pending.get(msg.id)?.(msg);
        this.pending.delete(msg.id);
      }
    });
  }
  request(body: object, timeoutMs = 5000): Promise<any> {
    const id = crypto.randomUUID();
    return new Promise((resolve, reject) => {
      const t = setTimeout(() => {
        this.pending.delete(id);
        reject(new Error("timeout"));
      }, timeoutMs);
      this.pending.set(id, (m) => { clearTimeout(t); resolve(m); });
      this.ws.send(JSON.stringify({ ...body, id }));
    });
  }
}

더 깊이

COMMENTS (…)

댓글을 불러오는 중이에요.

NEW COMMENT0 / 1000
⌘↵ 전송

blog92@web:~$ cd ..