Repository navigation
Stream LLM responses instead of blocking the servlet thread during generation #24
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or requestjavaPull requests that update java codePull requests that update java code
Description
Background
QueryService.generateWithTimeout (src/main/java/br/com/arquivolivre/myjavagenie/service/QueryService.java, ~line 260) runs the LLM call in CompletableFuture.supplyAsync (the common ForkJoinPool) and then blocks the servlet thread on future.get(timeoutSeconds, ...). The HTTP request stays open for up to query.timeout-seconds (300 s in the Docker profile) with no token streaming. The UI only receives the final answer via the REST response, plus coarse status updates over WebSocket.
Impact
- Tomcat worker threads are pinned for the entire generation duration, limiting concurrency under load.
- Perceived latency is high: users wait for the full answer with no partial tokens, even though the UI already streams status updates.
future.cancel(true)on timeout only interrupts the pool thread; the underlying provider HTTP request can keep running.- Using the common ForkJoinPool for blocking I/O can starve other async tasks in the JVM.
How to reproduce
- Set
query.timeout-seconds: 300andmodel.max-tokens: 4096. - Ask a question that produces a long answer.
- Observe
/api/chat/querystays pending for the full generation and no token-level output reaches the UI until completion.
Where the fix should land
Two complementary options (pick per scope):
- Short term: keep the timeout logic but return
Callable/DeferredResultfrom the controller via Spring MVC async so the servlet thread is released during generation. - Long term: use LangChain4j
StreamingChatModel(OpenAiStreamingChatModel) and push token deltas over the existing WebSocket (/ws/chat) or SSE, so the UI renders tokens as they arrive.
Files touched
src/main/java/br/com/arquivolivre/myjavagenie/service/QueryService.javasrc/main/java/br/com/arquivolivre/myjavagenie/controller/ChatController.javaand/orQueryController.javasrc/main/java/br/com/arquivolivre/myjavagenie/websocket/ChatWebSocketHandler.javachat-ui/src/context/ChatContext.tsx,chat-ui/src/services/websocket.ts(streaming UI)LanguageModelProvider/OpenAIModelProviderif a streaming method is added
Acceptance criteria
- Servlet threads are released during LLM generation (or responses are streamed).
- UI renders partial tokens (or, at minimum, no longer shows a spinner for the full duration).
- Timeout behavior preserved: still 504/
ModelTimeoutExceptionafterquery.timeout-seconds. - Existing
QueryServiceTestupdated and green;mvn spotless:checkpasses.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requestjavaPull requests that update java codePull requests that update java code
Activity