Imagine the use case when sending response does not happen from IO or worker thread, but instead originates as a part of asynchronous event handling in an application thread.

Below is a code snippet for a simple timer use case where response is meant to be sent in 5 seconds after receiving a request. This solution is put here just to illustrate the point, it does NOT work for the obvious reason that we'll cover later:

    final Undertow undertow = Undertow.builder()
            .addHttpListener(9090, "localhost")
            .setHandler(new HttpHandler() {
                public void handleRequest(final HttpServerExchange exchange) throws Exception {
                    new Timer().schedule(new TimerTask() {
                        public void run() {
                            exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                            exchange.getResponseSender().send("Returned in 5 seconds");
                        }
                    }, 5000);
                }
            }).build();
    undertow.start();

This handler is implemented incorrectly because exchange will end right after handleRequest method is called.

In order to fix this we can use dispatching (only implementation of handleRequest method is shown):

    public void handleRequest(final HttpServerExchange exchange) throws Exception {
        if (exchange.isInIoThread()) {
            exchange.dispatch(new Runnable() {
                public void run() {
                    new Timer().schedule(new TimerTask() {
                        public void run() {
                            Connectors.executeRootHandler(new HttpHandler() {
                                public void handleRequest(HttpServerExchange exchange) throws Exception {
                                    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                                    exchange.getResponseSender().send("Returned in 5 seconds");
                                }
                            }, exchange);
                        }
                    }, 5000);
                }
            });
        }
    }

Please pay attention that the requirement here is not to use dumb blocking in the work thread (like Thread.sleep(5000)) but rely on asynchronous event handling instead.

I would appreciate if someone can answer the following questions:
  • Are there any pitfalls with the working dispatch/executeRootHandler solution mentioned above?
  • Is there a simpler and more elegant way to achieve the same?
--
Vladimir Tsukur
Software Architect, Design Engineer and Scrum Master