Ian Chou's Blog

如果 Server 這端不回話,Client 就在那裡等死嗎? (Timeout 機制)

如果 Server 這端不回話,Client 就在那裡等死嗎? (Timeout 機制)

這是分散式系統中最令人頭痛的狀況:「無盡的等待」

直接回答:如果 Server「已讀不回」,Client 預設會一直傻等,直到達到「逾時時間」為止,然後由 Client 單方面切斷連線並報錯。

在 MCP 架構下,處理這種狀況有三道防線:

第一道防線:Client 端的「碼表」

Cursor 內部的程式碼概念上是這樣:

function callToolWithTimeout(toolName, params) {
  return Promise.race([
    sendJsonRpcRequest(toolName, params),
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error("Timeout")), 60000)
    )
  ]);
}

第二道防線:使用者的「停止鍵」

當你按下「Cancel」按鈕時,Cursor 會發送特殊的取消通知:

{
  "jsonrpc": "2.0",
  "method": "$/cancelRequest", 
  "params": { "requestId": 123 }
}

第三道防線:行程監控


作為開發者該如何避免?

1. 永遠不要信任外部 API

// ❌ 危險
const res = await fetch("https://slow-api.com/data");

2. 加上你自己的 Timeout

// ✅ 安全做法
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

try {
  const res = await fetch("...", { signal: controller.signal });
} catch (error) {
  if (error.name === 'AbortError') {
    return { 
      isError: true,
      content: [{ type: "text", text: "外部 API 連線逾時" }] 
    };
  }
}

總結