I try to realize how to build an true-async http server with Undertow. How to send a response asynchronously if I have another thread which one is processing a request already?
I wrote code like this:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(exchange -> {
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).thenAccept(string -> {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Hello World");
exchange.endExchange();
}).exceptionally(throwable -> {
System.out.println(throwable.toString());
return null;
});
}).build();
server.start();
but this server response 200 with no data and in logs
java.lang.IllegalStateException: UT000127: Response has already been sent
When I use io.undertow.server.HttpServerExchange#dispatch(java.lang.Runnable) method like this:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(exchange -> {
exchange.dispatch(() -> {
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).thenAccept(string -> {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE,"text/plain");
exchange.getResponseSender().send("Hello World");
exchange.endExchange();
}).exceptionally(throwable -> {
System.out.println(throwable.toString());
return null;
});
});
}).build();
server.start();
of course a response "Hello World" as expected but server creates new thread for every request!
If you call dispatch()
without passing an executor, like this:
exchange.dispatch(() -> {
//...
});
it will dispatch it to the XNIO worker thread pool. It will not necessarily "create new thread for every request".
If you want to not dispatch it to another thread, you should do this:
exchange.dispatch(SameThreadExecutor.INSTANCE, () -> {
//...
});