C.W.K.
Stream
Lesson 07 of 08 · published

Reconnection Strategy

~14 min · browser, reconnect, backoff

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

WebSocket 은 auto-reconnect 안 해

EventSource 와 달리 네이티브 브라우저 WebSocket 은 connection 끊겨도 재연결 안 해. 의도적이야: 재연결 정책은 application 마다 달라 — chat 은 공격적, one-shot streaming export 는 안 함. protocol 이 안 끼어들어.

Exponential backoff with jitter

업계 표준은 exponential backoff with jitter. 실패 후 min(base * 2^retry, cap) 초 기다리고, ±25% 의 randomized jitter 더해 — 10,000 클라가 동시에 재연결할 때 회복 중 서버에 lockstep 으로 떼지어 들이대지 않게 ('thundering herd'). 다음 성공 open 마다 retry 카운터 reset.

Close 1000 엔 skip

깨끗한 close (code 1000) 엔 재연결 하지 마 — application 이 요청한 거. 1001, 1006, 1011, 그리고 대부분 4xxx code 엔 재연결. 4001 (auth expired) 엔 무지성 재연결 대신 재인증 prompt 띄워.

Code

ReconnectingWebSocket — 최소이지만 정확·javascript
class ReconnectingWebSocket extends EventTarget {
  constructor(url, { maxRetries = Infinity, baseDelay = 1_000, capDelay = 30_000 } = {}) {
    super();
    this.url = url;
    this.maxRetries = maxRetries;
    this.baseDelay = baseDelay;
    this.capDelay = capDelay;
    this.retry = 0;
    this.shouldReconnect = true;
    this._connect();
  }

  _connect() {
    this.ws = new WebSocket(this.url);

    this.ws.addEventListener('open', () => {
      this.retry = 0;
      this.dispatchEvent(new Event('connected'));
    });

    this.ws.addEventListener('message', (e) => {
      this.dispatchEvent(new MessageEvent('message', { data: e.data }));
    });

    this.ws.addEventListener('close', (e) => {
      this.dispatchEvent(new CloseEvent('disconnected', { code: e.code, reason: e.reason }));

      const isCleanShutdown = e.code === 1000 || e.code === 4001;
      if (!this.shouldReconnect || isCleanShutdown) return;
      if (this.retry >= this.maxRetries) return;

      const base = Math.min(this.baseDelay * (2 ** this.retry), this.capDelay);
      const jitter = base * 0.25 * (Math.random() * 2 - 1);
      const delay = Math.max(0, base + jitter);

      this.retry += 1;
      setTimeout(() => this._connect(), delay);
    });
  }

  send(data) {
    if (this.ws?.readyState === WebSocket.OPEN) this.ws.send(data);
  }

  close(code = 1000, reason = '') {
    this.shouldReconnect = false;
    this.ws?.close(code, reason);
  }
}
Jitter 가 왜 — thundering herd·text
  Server crashes at t=0.
  10,000 clients all set their next reconnect for t = 1s, 2s, 4s, 8s, ...
  Without jitter, all 10,000 hit the recovering server at exactly t=1s.
  -> Server immediately overwhelmed and crashes again.

  With ±25% jitter:
  Reconnects spread across the 0.75-1.25s window, then the 1.5-2.5s window.
  Server sees a smooth ramp instead of a wall of traffic.

External links

Exercise

위 ReconnectingWebSocket 클래스 짜. 5초마다 connection drop 하게 서버 강제. devtools 에서 retry 가 jitter 와 함께 ~1, 2, 4, 8, 16초에 일어나는 거, 성공 재연결 후 카운터가 reset 되는 거 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.