OpenAI API 스트리밍 응답 처리 중 connection timeout 해결
문제 상황
GPT-4o API를 활용한 챗봇 서비스에서 스트리밍 응답을 구현했다. 짧은 답변은 문제없이 동작했지만, 1000 토큰 이상의 긴 응답에서 중간에 연결이 끊기는 현상이 발생했다.
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: messages,
stream: true,
});
에러 로그를 확인하니 ECONNRESET 에러가 발생했다. Vercel의 기본 function timeout이 10초로 설정되어 있었고, 긴 응답의 경우 이를 초과하는 것이 원인이었다.
해결 방법
1. Vercel function timeout 설정
vercel.json에서 타임아웃을 60초로 연장했다.
{
"functions": {
"app/api/chat/route.ts": {
"maxDuration": 60
}
}
}
2. 스트림 처리 개선
ReadableStream으로 변환하면서 주기적으로 데이터를 전송해 connection을 유지하도록 수정했다.
const stream = new ReadableStream({
async start(controller) {
for await (const chunk of response) {
const content = chunk.choices[0]?.delta?.content || '';
if (content) {
controller.enqueue(
new TextEncoder().encode(`data: ${JSON.stringify({ content })}\n\n`)
);
}
}
controller.close();
},
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
3. 클라이언트 재연결 로직
만약의 경우를 대비해 EventSource에 재연결 로직을 추가했다.
const eventSource = new EventSource('/api/chat');
eventSource.onerror = () => {
eventSource.close();
// 재시도 로직
};
결과
2000 토큰 이상의 긴 응답도 안정적으로 스트리밍되는 것을 확인했다. GPT-4o의 빠른 응답 속도 덕분에 실제로는 30초 이내에 대부분 완료되지만, 여유있게 설정해두는 것이 안전하다.