Search in sources :

Example 1 with ReturnValueWriter

use of com.palantir.conjure.java.undertow.lib.ReturnValueWriter in project conjure-java by palantir.

the class ConjureAsyncRequestProcessing method registerCallback.

private <T> void registerCallback(ListenableFuture<T> future, ReturnValueWriter<T> returnValueWriter, Duration requestAsyncTimeout, HttpServerExchange exchange) {
    // Attach data to the exchange in order to reuse a stateless listener
    exchange.putAttachment(FUTURE, future);
    // If the exchange is complete we still follow this path to provide standard logging.
    if (exchange.isComplete()) {
        // If the exchange has already completed (http/2 rst_stream while processing).
        // Calling addExchangeCompleteListener will result in an IllegalStateException in this case.
        future.cancel(INTERRUPT_ON_CANCEL);
    } else {
        // Cancel the future if the exchange is completed before the future is done
        exchange.addExchangeCompleteListener(COMPLETION_LISTENER);
    }
    XnioExecutor.Key timeoutKey = exchange.getIoThread().executeAfter(() -> {
        // TIMED_OUT must be set prior to future.cancel, otherwise the FutureCallback
        // may be invoked before TIMED_OUT is set/visible.
        exchange.putAttachment(TIMED_OUT, Boolean.TRUE);
        future.cancel(INTERRUPT_ON_CANCEL);
    }, requestAsyncTimeout.toMillis(), TimeUnit.MILLISECONDS);
    future.addListener(timeoutKey::remove, DIRECT_EXECUTOR);
    // Dispatch the registration task, this accomplishes two things:
    // 1. Puts the exchange into a 'dispatched' state, otherwise the request will be terminated when
    // the endpoint HttpHandler returns. See Connectors.executeRootHandler for more information.
    // 2. Avoids racing completion with the current handler chain. The dispatched task will be executed
    // after this Endpoints HttpHandler returns. Otherwise an unlucky future could race
    // HttpServerExchange.isInCall transitioning from true -> false, causing hte dispatch task not
    // to execute.
    DeferredTracer tracer = new DeferredTracer("Undertow: Async Result");
    exchange.dispatch(() -> Futures.addCallback(future, new FutureCallback<T>() {

        @Override
        public void onSuccess(@Nullable T result) {
            exchange.dispatch(wrapCallback(_serverExchange -> returnValueWriter.write(result, exchange), tracer));
        }

        @Override
        public void onFailure(Throwable throwable) {
            exchange.dispatch(wrapCallback(serverExchange -> exceptionHandler.handle(serverExchange, getThrowable(serverExchange, throwable, requestAsyncTimeout)), tracer));
        }
    }, DIRECT_EXECUTOR));
}
Also used : DeferredTracer(com.palantir.tracing.DeferredTracer) MoreExecutors(com.google.common.util.concurrent.MoreExecutors) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) HttpServerExchange(io.undertow.server.HttpServerExchange) ReturnValueWriter(com.palantir.conjure.java.undertow.lib.ReturnValueWriter) ExchangeCompletionListener(io.undertow.server.ExchangeCompletionListener) SafeArg(com.palantir.logsafe.SafeArg) Duration(java.time.Duration) DeferredTracer(com.palantir.tracing.DeferredTracer) XnioExecutor(org.xnio.XnioExecutor) Nullable(org.checkerframework.checker.nullness.qual.Nullable) CancellationException(java.util.concurrent.CancellationException) Executor(java.util.concurrent.Executor) AsyncRequestProcessing(com.palantir.conjure.java.undertow.lib.AsyncRequestProcessing) AttachmentKey(io.undertow.util.AttachmentKey) ErrorType(com.palantir.conjure.java.api.errors.ErrorType) IOException(java.io.IOException) ServiceException(com.palantir.conjure.java.api.errors.ServiceException) FutureCallback(com.google.common.util.concurrent.FutureCallback) Code(com.palantir.conjure.java.api.errors.ErrorType.Code) ExceptionHandler(com.palantir.conjure.java.undertow.lib.ExceptionHandler) HttpHandler(io.undertow.server.HttpHandler) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Futures(com.google.common.util.concurrent.Futures) Preconditions(com.palantir.logsafe.Preconditions) XnioExecutor(org.xnio.XnioExecutor) FutureCallback(com.google.common.util.concurrent.FutureCallback) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Aggregations

FutureCallback (com.google.common.util.concurrent.FutureCallback)1 Futures (com.google.common.util.concurrent.Futures)1 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)1 MoreExecutors (com.google.common.util.concurrent.MoreExecutors)1 ErrorType (com.palantir.conjure.java.api.errors.ErrorType)1 Code (com.palantir.conjure.java.api.errors.ErrorType.Code)1 ServiceException (com.palantir.conjure.java.api.errors.ServiceException)1 AsyncRequestProcessing (com.palantir.conjure.java.undertow.lib.AsyncRequestProcessing)1 ExceptionHandler (com.palantir.conjure.java.undertow.lib.ExceptionHandler)1 ReturnValueWriter (com.palantir.conjure.java.undertow.lib.ReturnValueWriter)1 Preconditions (com.palantir.logsafe.Preconditions)1 SafeArg (com.palantir.logsafe.SafeArg)1 DeferredTracer (com.palantir.tracing.DeferredTracer)1 ExchangeCompletionListener (io.undertow.server.ExchangeCompletionListener)1 HttpHandler (io.undertow.server.HttpHandler)1 HttpServerExchange (io.undertow.server.HttpServerExchange)1 AttachmentKey (io.undertow.util.AttachmentKey)1 IOException (java.io.IOException)1 Duration (java.time.Duration)1 CancellationException (java.util.concurrent.CancellationException)1