기존 방식의 문제
클라이언트에서 ActionCable 채널로 메시지를 보내면, 채널 액션 안에서 AI Agent API를 동기로 호출하고 응답을 기다린 뒤 broadcast하는 구조였다.
def send_message(data)
result = AiAgent.call(data['prompt']) # 최대 2분 블로킹
ActionCable.server.broadcast("channel_#{current_user.id}", result)
endAI Agent 응답이 최대 2분까지 걸릴 수 있는데, ActionCable 채널 액션은 Puma 스레드에서 실행된다. 즉, 응답을 기다리는 동안 스레드가 점유된다. Puma 스레드풀은 보통 10개 내외 수준이라, 동시 요청이 몇 개만 들어와도 스레드풀이 고갈되어 전체 서비스가 응답 불가 상태가 된다.
개선 방향
채널 액션에서는 Event publish 또는 Background(BG) job 을 enqueue만 하고 즉시 반환하고, AI Agent 호출은 백그라운드의 워커가 전담한다. 응답이 준비되면 다시 이벤트를 발행해 채널에서 broadcast한다.
개선 전
sequenceDiagram participant Client participant WebServer as Web Server (ActionCable) participant AiAgent as AI Agent Client->>WebServer: send_message WebServer->>AiAgent: API 호출 (블로킹) Note over WebServer: Puma 스레드 점유 AiAgent-->>WebServer: 응답 WebServer->>Client: broadcast
개선 후
sequenceDiagram participant Client participant WebServer as Web Server (ActionCable) participant BgWorker as BG Worker Client->>WebServer: send_message WebServer->>BgWorker: Event publish or Job enqueue WebServer-->>Client: AI Agent 호출 없이 반환 Note over WebServer: Puma 스레드 점유 안 함 BgWorker->>BgWorker: AI Agent 호출 (블로킹) BgWorker->>Client: broadcast (결과 전달)
Info
Puma 스레드는 이벤트 발행 후 즉시 반환되므로 스레드풀 고갈 문제가 해소된다.