From ff647aa6aee1b343e78aa87f6a6c3bb6ff34a67c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 23 Jun 2026 23:32:25 +0000 Subject: [PATCH] feat: offload incremental tool call DB save to background thread SSE event was blocked on disk I/O before reaching the client. Submitting the INSERT to the existing virtual-thread executor lets events.publish() run immediately after the tool finishes, while the write happens concurrently. The batch save in onComplete writes to a separate table (chat_message), so there is no ordering dependency. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_0185eo9C1XmDGioNAvUPweNv --- .../github/trialiya/kb/service/ChatRunService.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/io/github/trialiya/kb/service/ChatRunService.java b/backend/src/main/java/io/github/trialiya/kb/service/ChatRunService.java index 4ec4b6c..53430c9 100644 --- a/backend/src/main/java/io/github/trialiya/kb/service/ChatRunService.java +++ b/backend/src/main/java/io/github/trialiya/kb/service/ChatRunService.java @@ -167,11 +167,13 @@ private void run( payload -> { if (payload instanceof ToolCallMessage tcm) { if (tcm.toolCall().status() != ToolInvocationStatus.STARTED) { - chatMemoryService.saveToolCallIncremental( - conversationId, - runId, - tcm.toolCall().callIndex(), - tcm.toolCall()); + // DB write is best-effort bookkeeping; offload it so SSE goes out + // immediately without waiting for disk I/O. + final var tc = tcm.toolCall(); + executor.execute( + () -> + chatMemoryService.saveToolCallIncremental( + conversationId, runId, tc.callIndex(), tc)); } } events.publish(conversationId, eventType(payload), runId, null, payload);