Skip to content

Commit 28f46f0

Browse files
committed
refactor(appserver): close 改为关自持 ExecutorService——HttpClient.close() 为 JDK 21 API,与 2.0.x 线保持实现一致;测试助手 readTree 统一包裹异常
1 parent 2c15db6 commit 28f46f0

3 files changed

Lines changed: 24 additions & 9 deletions

File tree

‎src/main/java/io/github/easy4j/codex/appserver/CodexAppServerClient.java‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.util.Objects;
2121
import java.util.concurrent.CompletableFuture;
2222
import java.util.concurrent.CompletionException;
23+
import java.util.concurrent.ExecutorService;
24+
import java.util.concurrent.Executors;
2325

2426
import tools.jackson.databind.DeserializationFeature;
2527
import tools.jackson.databind.ObjectMapper;
@@ -72,6 +74,11 @@ public class CodexAppServerClient implements AutoCloseable {
7274
JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
7375
private final ThreadMappingCache threadBySession;
7476
private final Object httpClientLock = new Object();
77+
private final ExecutorService clientExecutor = Executors.newCachedThreadPool(r -> {
78+
Thread thread = new Thread(r, "codex-app-server-client");
79+
thread.setDaemon(true);
80+
return thread;
81+
});
7582

7683
private volatile HttpClient httpClient;
7784
private volatile boolean closed;
@@ -145,16 +152,15 @@ public CodexAppServerConfig getConfig() {
145152
}
146153

147154
/**
148-
* Closes the client. New turns are rejected afterwards; the shared
149-
* {@link HttpClient} is shut down once any in-flight turn completes.
155+
* Closes the client. New turns are rejected afterwards; the executor
156+
* backing the shared {@link HttpClient} is shut down gracefully. The
157+
* executor is owned by this client so closing works on every JDK line
158+
* ({@code HttpClient.close()} only exists since JDK 21).
150159
*/
151160
@Override
152161
public void close() {
153162
closed = true;
154-
HttpClient client = httpClient;
155-
if (Objects.nonNull(client)) {
156-
client.close();
157-
}
163+
clientExecutor.shutdown();
158164
}
159165

160166
private HttpClient httpClient() {
@@ -164,6 +170,7 @@ private HttpClient httpClient() {
164170
if (Objects.isNull(httpClient)) {
165171
httpClient = HttpClient.newBuilder()
166172
.connectTimeout(Duration.ofMillis(config.getConnectTimeoutMillis()))
173+
.executor(clientExecutor)
167174
.build();
168175
}
169176
client = httpClient;

‎src/test/java/io/github/easy4j/codex/appserver/CodexAppServerClientE2ETest.java‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,12 @@ void shouldCompleteTurnWithoutSessionKey() throws Exception {
123123
}
124124

125125
private String methodOf(String frame) {
126-
JsonNode node = mapper.readTree(frame);
127-
return node.path("method").asText("");
126+
try {
127+
JsonNode node = mapper.readTree(frame);
128+
return node.path("method").asText("");
129+
} catch (Exception ex) {
130+
throw new IllegalStateException("Invalid JSON-RPC frame: " + frame, ex);
131+
}
128132
}
129133

130134
private List<String> methodsOf(FakeCodexAppServer server) {

‎src/test/java/io/github/easy4j/codex/appserver/CodexAppServerTurnTest.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ private CodexAppServerTurn newTurn(AppServerTurnRequest request, ThreadMappingCa
4848
}
4949

5050
private JsonNode lastFrame(List<String> sent) {
51-
return mapper.readTree(sent.get(sent.size() - 1));
51+
try {
52+
return mapper.readTree(sent.get(sent.size() - 1));
53+
} catch (Exception ex) {
54+
throw new IllegalStateException("Invalid captured frame", ex);
55+
}
5256
}
5357

5458
@Test

0 commit comments

Comments
 (0)