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

WebSocket 위 Request-Response

~13 min · protocol, correlation-id, promises

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

WebSocket 은 default 가 fire-and-forget

Protocol 이 '이 특정 message 의 응답 기다려' 안 줘. 모든 message 가 독립. request-response semantic 만들려면 — '이 user data fetch', '이 setting 저장', 클라가 확인 원하는 모든 거 — correlation ID 추가: 클라가 고른 unique ID, 서버가 echo back, 클라가 매칭에 사용.

Promise 로 wrap 한 request

클라쪽 ergonomic 은 작은 Promise wrapper. await ws.request('user.get', {id: 'x'}) 가 응답 data 리턴. 내부: UUID 픽, resolver 등록, send, wait. timeout 추가 — 응답 안 오는 것도 가능한 결과니까.

Code

Promise 로 wrap 한 request·javascript
const pending = new Map(); // id -> { resolve, reject, timer }

function request(ws, type, data, timeoutMs = 10_000) {
  return new Promise((resolve, reject) => {
    const id = crypto.randomUUID();
    const timer = setTimeout(() => {
      pending.delete(id);
      reject(new Error(`timeout: ${type}`));
    }, timeoutMs);
    pending.set(id, { resolve, reject, timer });
    ws.send(JSON.stringify({ id, type, data }));
  });
}

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.id && pending.has(msg.id)) {
    const entry = pending.get(msg.id);
    pending.delete(msg.id);
    clearTimeout(entry.timer);
    if (msg.type === 'error') entry.reject(new Error(msg.message));
    else                      entry.resolve(msg.data);
    return;
  }
  // Unsolicited event — push, not response
  handleEvent(msg);
};

// Usage
const user = await request(ws, 'user.get', { id: '123' });
서버 쪽 — id echo back·python
async def handle(ws, msg):
    rid = msg.get('id')
    typ = msg.get('type')
    data = msg.get('data', {})
    try:
        result = await dispatch(typ, data)
        await ws.send_json({
            'id': rid,
            'type': f'{typ}.response',
            'data': result,
        })
    except Exception as e:
        await ws.send_json({
            'id': rid,
            'type': 'error',
            'code': type(e).__name__,
            'message': str(e),
        })

External links

Exercise

request() 와 echoed id 응답하는 서버쪽 짜. 동시 5 request 테스트; 응답이 out-of-order 도착해도 옳게 매칭되는지 확인. 서버가 한 request 를 15초 잡고 있게 — 클라가 10s 에 timeout 하고 나머지는 정상 resolve.

Progress

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

댓글 0

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

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