@Override public ExecutorService blockingTaskExecutor() { return delegate().blockingTaskExecutor(); }
/** * Returns a {@link CompletionStage} object. The {@link JacksonResponseConverterFunction} will * be executed after the future is completed with the {@link Response} object. * * <p>Note that the {@link ServiceRequestContext} of the request is also automatically injected. See * <a href="https://line.github.io/armeria/server-annotated-service.html#other-classes-automatically-injected"> * Other classes automatically injected</a> for more information. */ @Post("/obj/future") @ProducesJson public CompletionStage<Response> json4(@RequestObject Request request, ServiceRequestContext ctx) { final CompletableFuture<Response> future = new CompletableFuture<>(); ctx.blockingTaskExecutor() .submit(() -> future.complete(new Response(Response.SUCCESS, request.name()))); return future; }
@Override public void endOfStream() { setClientStreamClosed(); if (!closeCalled) { if (!ctx.log().isAvailable(RequestLogAvailability.REQUEST_CONTENT)) { ctx.logBuilder().requestContent(GrpcLogUtil.rpcRequest(method), null); } if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeHalfClose); } else { invokeHalfClose(); } } }
private void doSendMessage(O message) { checkState(sendHeadersCalled, "sendHeaders has not been called"); checkState(!closeCalled, "call is closed"); if (firstResponse == null) { firstResponse = message; } try { res.write(messageFramer.writePayload(marshaller.serializeResponse(message))); res.onDemand(() -> { if (pendingMessagesUpdater.decrementAndGet(this) == 0) { if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnReady); } else { invokeOnReady(); } } }); } catch (RuntimeException e) { close(Status.fromThrowable(e), EMPTY_METADATA); throw e; } catch (Throwable t) { close(Status.fromThrowable(t), EMPTY_METADATA); throw new RuntimeException(t); } }
if (newStatus.isOk()) { if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnComplete); } else { invokeOnComplete(); cancelled = true; if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnCancel); } else { invokeOnCancel();
@Override @SuppressWarnings("unchecked") public HttpResponse convertResponse(ServiceRequestContext ctx, HttpHeaders headers, @Nullable Object result, HttpHeaders trailingHeaders) throws Exception { final CompletableFuture<?> f; if (result instanceof Publisher) { f = collectFrom((Publisher<Object>) result); } else if (result instanceof Stream) { f = collectFrom((Stream<Object>) result, ctx.blockingTaskExecutor()); } else { return ResponseConverterFunction.fallthrough(); } assert f != null; return HttpResponse.from(f.handle((aggregated, cause) -> { if (cause != null) { return exceptionHandler.handleException(ctx, ctx.request(), cause); } try { return responseConverter.convertResponse(ctx, headers, aggregated, trailingHeaders); } catch (Exception e) { return exceptionHandler.handleException(ctx, ctx.request(), e); } })); } }
/** * Executes the service method in different ways regarding its return type and whether the request is * required to be aggregated. If the return type of the method is not a {@link CompletionStage} or * {@link HttpResponse}, it will be executed in the blocking task executor. */ private CompletionStage<HttpResponse> serve0(ServiceRequestContext ctx, HttpRequest req) { final CompletableFuture<AggregatedHttpMessage> f = aggregationRequired(aggregationStrategy, req) ? req.aggregate() : CompletableFuture.completedFuture(null); ctx.setAdditionalResponseHeaders(defaultHttpHeaders); ctx.setAdditionalResponseTrailers(defaultHttpTrailers); switch (responseType) { case HTTP_RESPONSE: return f.thenApply( msg -> new ExceptionFilteredHttpResponse(ctx, req, (HttpResponse) invoke(ctx, req, msg), exceptionHandler)); case COMPLETION_STAGE: return f.thenCompose(msg -> toCompletionStage(invoke(ctx, req, msg))) .handle((result, cause) -> cause == null ? convertResponse(ctx, req, null, result, HttpHeaders.EMPTY_HEADERS) : exceptionHandler.handleException(ctx, req, cause)); default: return f.thenApplyAsync(msg -> convertResponse(ctx, req, null, invoke(ctx, req, msg), HttpHeaders.EMPTY_HEADERS), ctx.blockingTaskExecutor()); } }
coyoteRes.setOutputBuffer((OutputBuffer) OUTPUT_BUFFER_CONSTRUCTOR.invoke(data)); ctx.blockingTaskExecutor().execute(() -> { if (!res.isOpen()) { return;
@Override public HttpResponse convertResponse(ServiceRequestContext ctx, HttpHeaders headers, @Nullable Object result, HttpHeaders trailingHeaders) throws Exception { final MediaType mediaType = headers.contentType(); if (mediaType != null) { // @Produces("text/plain") or @ProducesText is specified. if (mediaType.is(MediaType.ANY_TEXT_TYPE)) { // Use 'utf-8' charset by default. final Charset charset = mediaType.charset().orElse(StandardCharsets.UTF_8); // To avoid sending an unfinished text to the client, always aggregate the published strings. if (result instanceof Publisher) { return aggregateFrom((Publisher<?>) result, headers, trailingHeaders, o -> toHttpData(o, charset)); } if (result instanceof Stream) { return aggregateFrom((Stream<?>) result, headers, trailingHeaders, o -> toHttpData(o, charset), ctx.blockingTaskExecutor()); } return HttpResponse.of(headers, toHttpData(result, charset), trailingHeaders); } } else if (result instanceof CharSequence) { return HttpResponse.of(toMutableHeaders(headers).contentType(MediaType.PLAIN_TEXT_UTF_8), HttpData.ofUtf8(((CharSequence) result).toString()), trailingHeaders); } return ResponseConverterFunction.fallthrough(); }
this::toJsonHttpData, ctx.blockingTaskExecutor()); this::toJsonSequencesHttpData, ctx.blockingTaskExecutor());
ctx.blockingTaskExecutor().execute(() -> invoke(ctx, res, transport, httpChannel)); success = true; return null;
private static void invokeSynchronously( ServiceRequestContext ctx, Object impl, ThriftFunction func, TBase<?, ?> args, DefaultRpcResponse reply) { final ProcessFunction<Object, TBase<?, ?>> f = func.syncFunc(); ctx.blockingTaskExecutor().execute(() -> { if (reply.isDone()) { // Closed already most likely due to timeout. return; } try { if (func.isOneWay()) { reply.complete(null); f.getResult(impl, args); } else { final TBase<?, ?> result = f.getResult(impl, args); reply.complete(func.getResult(result)); } } catch (Throwable t) { if (func.isOneWay()) { reply.complete(null); logOneWayFunctionFailure(ctx, t); } else { reply.completeExceptionally(t); } } }); }
ctx.blockingTaskExecutor().execute(() -> invokeOnMessage(request)); } else { invokeOnMessage(request);
final HttpResponse res = read(ctx.blockingTaskExecutor(), ctx.alloc()); if (res != null) { return res;
return streamingFrom((Stream<?>) result, headers, trailingHeaders, ByteArrayResponseConverterFunction::toHttpData, ctx.blockingTaskExecutor());
@Override public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception { return HttpResponse.from(CompletableFuture.supplyAsync(() -> { final AggregatedHttpMessage msg = req.aggregate().join(); final String sessionId = AuthTokenExtractors.OAUTH2.apply(msg.headers()).accessToken(); if (!WRONG_SESSION_ID.equals(sessionId)) { logoutSessionPropagator.apply(sessionId).join(); } return HttpResponse.of(HttpStatus.OK); }, ctx.blockingTaskExecutor())); } }
@Override public void endOfStream() { setClientStreamClosed(); if (!closeCalled) { if (!ctx.log().isAvailable(RequestLogAvailability.REQUEST_CONTENT)) { ctx.logBuilder().requestContent(GrpcLogUtil.rpcRequest(method), null); } if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeHalfClose); } else { invokeHalfClose(); } } }
private static void invokeSynchronously( ServiceRequestContext ctx, Object impl, ThriftFunction func, TBase<?, ?> args, DefaultRpcResponse reply) { final ProcessFunction<Object, TBase<?, ?>> f = func.syncFunc(); ctx.blockingTaskExecutor().execute(() -> { if (reply.isDone()) { // Closed already most likely due to timeout. return; } try { final TBase<?, ?> result = f.getResult(impl, args); if (func.isOneWay()) { reply.complete(null); } else { reply.complete(func.getResult(result)); } } catch (Throwable t) { reply.completeExceptionally(t); } }); } }
private void doSendMessage(O message) { checkState(sendHeadersCalled, "sendHeaders has not been called"); checkState(!closeCalled, "call is closed"); if (firstResponse == null) { firstResponse = message; } try { res.write(messageFramer.writePayload(marshaller.serializeResponse(message))); res.onDemand(() -> { if (pendingMessagesUpdater.decrementAndGet(this) == 0) { if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnReady); } else { invokeOnReady(); } } }); } catch (RuntimeException e) { close(Status.fromThrowable(e), EMPTY_METADATA); throw e; } catch (Throwable t) { close(Status.fromThrowable(t), EMPTY_METADATA); throw new RuntimeException(t); } }
private static void invokeSynchronously( ServiceRequestContext ctx, Object impl, ThriftFunction func, TBase<?, ?> args, DefaultRpcResponse reply) { final ProcessFunction<Object, TBase<?, ?>> f = func.syncFunc(); ctx.blockingTaskExecutor().execute(() -> { if (reply.isDone()) { // Closed already most likely due to timeout. return; } try { if (func.isOneWay()) { reply.complete(null); f.getResult(impl, args); } else { final TBase<?, ?> result = f.getResult(impl, args); reply.complete(func.getResult(result)); } } catch (Throwable t) { if (func.isOneWay()) { reply.complete(null); logOneWayFunctionFailure(ctx, t); } else { reply.completeExceptionally(t); } } }); }