Skip to content

Commit 15ee11e

Browse files
committed
fix(appserver): serialize turn websocket writes
1 parent b5856b9 commit 15ee11e

1 file changed

Lines changed: 28 additions & 11 deletions

File tree

src/main/java/io/github/easy4j/codex/appserver/CodexAppServerTurn.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class CodexAppServerTurn implements WebSocket.Listener {
7878
private final List<String> sentMessages = new ArrayList<>();
7979

8080
private volatile WebSocket webSocket;
81+
private volatile CodexWebSocketSender sender;
8182
private volatile String threadId;
8283
private volatile String turnId;
8384

@@ -130,6 +131,7 @@ CompletableFuture<AppServerTurnResult> start() {
130131
@Override
131132
public void onOpen(WebSocket socket) {
132133
this.webSocket = socket;
134+
this.sender = new CodexWebSocketSender(socket);
133135
socket.request(1);
134136
begin();
135137
}
@@ -146,10 +148,18 @@ public void onOpen(WebSocket socket) {
146148
*/
147149
void begin() {
148150
CompletableFuture<JsonNode> initRpc = newRpc(CodexAppServerProtocol.INITIALIZE, buildInitializeParams());
149-
initRpc.thenAccept(result -> {
150-
sendNotification(CodexAppServerProtocol.INITIALIZED);
151-
startOrResumeThread();
152-
}).exceptionally(error -> {
151+
initRpc.thenAccept(result ->
152+
sendNotification(CodexAppServerProtocol.INITIALIZED)
153+
.whenComplete((ignored, sendError) -> {
154+
if (Objects.nonNull(sendError)) {
155+
completeError(new CodexAppServerException(
156+
"Codex initialized notification send failed",
157+
unwrap(sendError)));
158+
return;
159+
}
160+
startOrResumeThread();
161+
})
162+
).exceptionally(error -> {
153163
completeError(unwrap(error));
154164
return null;
155165
});
@@ -320,7 +330,13 @@ private CompletableFuture<JsonNode> newRpc(String method, Map<String, Object> pa
320330
completeError(unwrap(error));
321331
return null;
322332
});
323-
sendText(toJson(payload));
333+
sendText(toJson(payload)).whenComplete((ignored, sendError) -> {
334+
if (Objects.nonNull(sendError)) {
335+
rpc.completeExceptionally(new CodexAppServerException(
336+
"Codex WebSocket send failed for " + method,
337+
unwrap(sendError)));
338+
}
339+
});
324340
return rpc;
325341
}
326342

@@ -341,11 +357,11 @@ Map<String, Object> buildInitializeParams() {
341357
return params;
342358
}
343359

344-
private void sendNotification(String method) {
360+
private CompletionStage<WebSocket> sendNotification(String method) {
345361
Map<String, Object> payload = new LinkedHashMap<>();
346362
payload.put("jsonrpc", "2.0");
347363
payload.put("method", method);
348-
sendText(toJson(payload));
364+
return sendText(toJson(payload));
349365
}
350366

351367
Map<String, Object> buildTurnStartParams(String targetThreadId) {
@@ -365,12 +381,13 @@ private void rememberThreadMapping() {
365381
}
366382
}
367383

368-
private void sendText(String text) {
384+
private CompletionStage<WebSocket> sendText(String text) {
369385
sentMessages.add(text);
370-
WebSocket socket = webSocket;
371-
if (Objects.nonNull(socket)) {
372-
socket.sendText(text, true);
386+
CodexWebSocketSender currentSender = sender;
387+
if (Objects.isNull(currentSender)) {
388+
return CompletableFuture.completedFuture(webSocket);
373389
}
390+
return currentSender.send(text);
374391
}
375392

376393
private void close() {

0 commit comments

Comments
 (0)