ในระบบที่มีการเรียกใช้ API หลายตัวแบบ chain หรือ nested การจัดการ timeout ที่ไม่ดีอาจทำให้เกิดปัญหา cascade failure และ resource exhaustion ได้ บทความนี้จะอธิบายแนวทางการกำหนด global timeout และ single point timeout อย่างมีประสิทธิภาพ พร้อมโค้ด production-ready ที่ใช้งานได้จริง

ปัญหาของ Timeout ที่ไม่เหมาะสม

จากประสบการณ์ที่ใช้งาน production system ที่มี latency สูง พบว่าปัญหาหลักมักเกิดจาก:

Global Timeout vs Single Point Timeout

การกำหนด timeout มี 2 แนวทางหลัก:

Global Timeout

กำหนด timeout เดียวครอบทั้ง operation เหมาะกับ user-facing request ที่ต้องการ guarantee ว่าจะ respond ภายในเวลาที่กำหนด

Single Point Timeout

กำหนด timeout แยกสำหรับแต่ละ API call ใน chain เหมาะกับ complex workflow ที่แต่ละ step มี SLA ต่างกัน

การใช้งานกับ HolySheep AI

สมัครที่นี่ เพื่อทดลองใช้งาน HolySheep AI — ผู้ให้บริการ LLM API ที่มี latency <50ms และราคาประหยัดกว่า 85% เมื่อเทียบกับ OpenAI โดยอัตรา ¥1=$1 รองรับ WeChat และ Alipay

// Global Timeout Configuration — ใช้ AbortController
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';

// Global timeout 30 วินาทีสำหรับทุก request
const GLOBAL_TIMEOUT_MS = 30000;

class GlobalTimeoutManager {
  private controller: AbortController;
  private timeoutId: NodeJS.Timeout;

  constructor(timeoutMs: number = GLOBAL_TIMEOUT_MS) {
    this.controller = new AbortController();
    this.timeoutId = setTimeout(() => {
      this.controller.abort();
    }, timeoutMs);
  }

  getSignal(): AbortSignal {
    return this.controller.signal;
  }

  cancel(): void {
    clearTimeout(this.timeoutId);
    this.controller.abort();
  }
}

// ตัวอย่างการใช้งาน
async function callWithGlobalTimeout<T>(
  apiCall: (signal: AbortSignal) => Promise<T>
): Promise<T> {
  const manager = new GlobalTimeoutManager(30000);
  try {
    return await apiCall(manager.getSignal());
  } finally {
    manager.cancel();
  }
}

// Benchmark: global timeout overhead ~0.1ms
const result = await callWithGlobalTimeout(async (signal) => {
  const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
    method: 'POST',
    headers: {
      'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'gpt-4.1',
      messages: [{ role: 'user', content: 'Hello' }],
    }),
    signal, // AbortSignal สำหรับ global timeout
  });
  return response.json();
});

Single Point Timeout สำหรับ API Chain

ในกรณีที่มีหลาย API calls ใน chain การกำหนด timeout แยกแต่ละจุดจะช่วยให้ควบคุมได้ละเอียดกว่า:

// Single Point Timeout — กำหนด timeout แยกสำหรับแต่ละ API
interface TimeoutConfig {
  embedding: number;  // สำหรับ embedding API — 5 วินาที
  completion: number; // สำหรับ completion API — 30 วินาที
  rerank: number;     // สำหรับ rerank API — 10 วินาที
}

const TIMEOUT_CONFIG: TimeoutConfig = {
  embedding: 5000,
  completion: 30000,
  rerank: 10000,
};

// Utility function สำหรับ timeout แบบ single point
async function withTimeout<T>(
  promise: Promise<T>,
  timeoutMs: number,
  operationName: string
): Promise<T> {
  const timeoutPromise = new Promise<never>((_, reject) => {
    setTimeout(() => {
      reject(new Error(${operationName} timeout after ${timeoutMs}ms));
    }, timeoutMs);
  });

  return Promise.race([promise, timeoutPromise]);
}

// Production example — RAG pipeline กับ HolySheep
async function ragPipeline(query: string): Promise<string> {
  const { Embedding, Rerank } = await import('@holysheepai/sdk');

  // Step 1: Embedding (5s timeout)
  const embeddingResult = await withTimeout(
    new Embedding({
      apiKey: process.env.HOLYSHEEP_API_KEY!,
      baseURL: HOLYSHEEP_BASE_URL,
    }).create({
      model: 'text-embedding-3-small',
      input: query,
    }),
    TIMEOUT_CONFIG.embedding,
    'Embedding'
  );

  // Step 2: Vector search (internal, 100ms)
  const searchResults = await withTimeout(
    vectorStore.search(embeddingResult.data[0].embedding, { topK: 10 }),
    100,
    'VectorSearch'
  );

  // Step 3: Rerank (10s timeout)
  const rerankResult = await withTimeout(
    new Rerank({
      apiKey: process.env.HOLYSHEEP_API_KEY!,
      baseURL: HOLYSHEEP_BASE_URL,
    }).create({
      model: 'rerank-v2.5',
      query,
      documents: searchResults.map(r => r.text),
      topN: 3,
    }),
    TIMEOUT_CONFIG.rerank,
    'Rerank'
  );

  // Step 4: Final completion (30s timeout)
  const context = rerankResult.results.map(r => r.document).join('\n');
  const completion = await withTimeout(
    fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
      method: 'POST',
      headers: {
        'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4.1',
        messages: [
          { role: 'system', content: Context: ${context} },
          { role: 'user', content: query },
        ],
      }),
    }).then(r => r.json()),
    TIMEOUT_CONFIG.completion,
    'Completion'
  );

  return completion.choices[0].message.content;
}

Advanced: Circuit Breaker Pattern

เมื่อรวมกับ circuit breaker จะช่วยป้องกัน cascade failure ได้ดีขึ้น:

// Circuit Breaker with Timeout
class CircuitBreakerWithTimeout {
  private failures = 0;
  private lastFailureTime = 0;
  private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';

  constructor(
    private threshold: number = 5,
    private timeout: number = 60000,
    private resetTimeout: number = 30000
  ) {}

  async execute<T>(
    fn: () => Promise<T>,
    operationTimeout: number
  ): Promise<T> {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
        this.state = 'HALF_OPEN';
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }

    try {
      const result = await withTimeout(fn(), operationTimeout, 'Operation');
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private onSuccess(): void {
    this.failures = 0;
    this.state = 'CLOSED';
  }

  private onFailure(): void {
    this.failures++;
    this.lastFailureTime = Date.now();
    if (this.failures >= this.threshold) {
      this.state = 'OPEN';
      console.log(Circuit breaker opened after ${this.failures} failures);
    }
  }

  getState(): string {
    return this.state;
  }
}

// ใช้งานกับ HolySheep API
const breaker = new CircuitBreakerWithTimeout(5, 60000, 30000);

async function resilientChat(messages: any[]): Promise<any> {
  return breaker.execute(
    () =>
      fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
        method: 'POST',
        headers: {
          'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          model: 'gpt-4.1',
          messages,
        }),
      }).then(r => r.json()),
    30000 // 30s timeout
  );
}

ราคาและ Benchmark

Modelราคา ($/MTok)Latency (P50)
GPT-4.1$8.00~120ms
Claude Sonnet 4.5$15.00~150ms
Gemini 2.5 Flash$2.50~45ms
DeepSeek V3.2$0.42~80ms

จากการ benchmark บน production workload พบว่า:

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

1. Timeout ไม่ทำงานเมื่อใช้ response.body

// ❌ วิธีที่ผิด — streaming response ทำให้ timeout ไม่ทำงาน
async function streamChat(messages: any[]) {
  const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
    method: 'POST',
    headers: {
      'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'gpt-4.1',
      messages,
      stream: true,
    }),
  });

  // Timeout ไม่ทำงานกับ streaming
  const timeout = setTimeout(() => {
    throw new Error('Timeout'); // ไม่สามารถ cancel stream ได้
  }, 30000);

  for await (const chunk of response.body) {
    // process chunk
  }
  clearTimeout(timeout);
}

// ✅ วิธีที่ถูก — ใช้ AbortController กับ streaming
async function streamChatWithTimeout(messages: any[]) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 30000);

  try {
    const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
      method: 'POST',
      headers: {
        'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'gpt-4.1',
        messages,
        stream: true,
      }),
      signal: controller.signal, // AbortController สำหรับ cancel streaming
    });

    const reader = response.body!.getReader();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      // process chunk
    }
  } finally {
    clearTimeout(timeoutId);
  }
}

2. Retry loop ไม่มีท่าออกเมื่อ service down

// ❌ วิธีที่ผิด — infinite retry เมื่อ service down
async function chatWithRetry(messages: any[]) {
  while (true) {
    try {
      const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
        method: 'POST',
        headers: {
          'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ model: 'gpt-4.1', messages }),
      });
      return response.json();
    } catch (e) {
      console.log('Retrying...'); // รอนานเกินไป
      await new Promise(r => setTimeout(r, 1000));
    }
  }
}

// ✅ วิธีที่ถูก — exponential backoff พร้อม circuit breaker
async function chatWithSmartRetry(
  messages: any[],
  maxAttempts: number = 3,
  breaker: CircuitBreakerWithTimeout
): Promise<any> {
  let lastError: Error | null = null;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await breaker.execute(
        () =>
          fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
            method: 'POST',
            headers: {
              'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ model: 'gpt-4.1', messages }),
          }).then(r => r.json()),
        30000
      );
    } catch (error: any) {
      lastError = error;
      console.log(Attempt ${attempt} failed: ${error.message});

      if (attempt < maxAttempts) {
        // Exponential backoff: 1s, 2s, 4s
        const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
        await new Promise(r => setTimeout(r, delay));
      }
    }
  }

  throw new Error(All ${maxAttempts} attempts failed: ${lastError?.message});
}

3. Timeout นาнееจนทำให้ memory leak

// ❌ วิธีที่ผิด — timeout นานเกินไปทำให้ memory เพิ่ม
async function batchProcess(queries: string[]) {
  const results = [];
  for (const query of queries) {
    const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
      method: 'POST',
      headers: {
        'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ model: 'gpt-4.1', messages: [{ role: 'user', content: query }] }),
    });
    // 60 วินาที timeout — เก็บ response ไว้ใน memory
    results.push(await response.json());
  }
  return results;
}

// ✅ วิธีที่ถูก — concurrency control พร้อม proper cleanup
async function batchProcessOptimized(queries: string[], concurrency: number = 5) {
  const results: any[] = [];
  const queue = [...queries];
  const activePromises: Promise<any>[] = [];

  while (queue.length > 0 || activePromises.length > 0) {
    // เติม active slots
    while (activePromises.length < concurrency && queue.length > 0) {
      const query = queue.shift()!;
      const promise = withTimeout(
        fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
          method: 'POST',
          headers: {
            'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ model: 'gpt-4.1', messages: [{ role: 'user', content: query }] }),
        }).then(r => r.json()),
        10000, // 10 วินาที timeout ต่อ request
        Batch-${query.slice(0, 20)}
      ).then(result => {
        results.push(result);
        return result;
      }).catch(err => {
        console.error(Query failed: ${err.message});
        return null; // ไม่เก็บ error ใน memory
      });

      activePromises.push(promise);
    }

    // รอให้ slot ว่าง
    if (activePromises.length > 0) {
      await Promise.race(activePromises.map((p, i) => p.then(() => i)));
      // Remove completed promises
      const completed: number[] = [];
      activePromises.forEach((p, i) => {
        if (p !== null && (p as any).status === 'fulfilled') {
          completed.push(i);
        }
      });
      activePromises.splice(0, completed.length);
    }
  }

  return results.filter(r => r !== null);
}

4. ไม่จัดการ partial failure ใน parallel requests

// ❌ วิธีที่ผิด — parallel requests พร้อม timeout ที่ fail ทั้งหมด
async function parallelCalls(ids: string[]) {
  const timeout = 5000; // 5 วินาที
  const promises = ids.map(id =>
    withTimeout(
      fetch(${HOLYSHEEP_BASE_URL}/models/${id}, {
        headers: { 'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY} },
      }).then(r => r.json()),
      timeout,
      id
    )
  );

  // ถ้า 1 ใน 10 fail ทั้งหมด fail
  return Promise.all(promises);
}

// ✅ วิธีที่ถูก — Promise.allSettled พร้อม result validation
async function parallelCallsSafe(ids: string[]) {
  const timeout = 5000;
  const promises = ids.map(id =>
    withTimeout(
      fetch(${HOLYSHEEP_BASE_URL}/models/${id}, {
        headers: { 'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY} },
      }).then(async r => {
        const data = await r.json();
        if (!r.ok) throw new Error(data.error?.message || HTTP ${r.status});
        return { id, data };
      }),
      timeout,
      id
    ).catch(err => ({ id, error: err.message, success: false }))
  );

  // รอทุก request เสร็จ ไม่ว่าจะ success หรือ fail
  const results = await Promise.allSettled(promises);

  // แยก success และ failure
  const successful = results
    .filter(r => r.status === 'fulfilled' && (r.value as any).success !== false)
    .map(r => (r as any).value);

  const failed = results
    .filter(r => r.status === 'rejected' || (r.value as any).success === false)
    .map(r => ({
      id: (r as any).value?.id || 'unknown',
      error: (r as any).value?.error || r.reason?.message
    }));

  return {
    successful,
    failed,
    summary: {
      total: ids.length,
      succeeded: successful.length,
      failed: failed.length,
    }
  };
}

สรุป

การจัดการ timeout ที่ดีต้องพิจารณา:

การใช้งาน HolySheep AI ที่มี latency <50ms ช่วยให้สามารถกำหนด timeout ที่สั้นลงได้ ลด risk ของ resource exhaustion และประหยัด cost ได้ถึง 85% เมื่อเทียบกับ OpenAI

👉 สมัคร HolySheep AI — รับเครดิตฟรีเมื่อลงทะเบียน