如何立即发送请求的异步响应

时间:2017-07-24 14:26:51

标签: java asynchronous java-8 jetty completable-future

我正在尝试找到一种异步方式来立即返回客户端请求的响应。

我需要的只是记录请求数据,调用新线程来请求在其他服务器上进行昂贵的操作(一些后端操作) 并且无需等待他们的回复,立即向客户返回200状态响应。

此刻我正在尝试使用CompletableFuture,但我遗漏了一些东西。

package com.example.controller;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.concurrent.CompletableFuture;

@Path("/class")
public class AsynchronousResponse {

private static final Logger LOGGER = (Logger) LogManager.getLogger(AsynchronousResponse.class.getName());
private static final int HTTP_STATUS_OK = 200;
private static final String EMPTY_CONTENT = "";

@Context
private HttpServletRequest httpRequest;

@Path("/method")
@GET
@Consumes(MediaType.APPLICATION_JSON)
public Response asyncResponseSupply() {
    LOGGER.info(httpRequest.getSession().getId() + " : New session received");
    CompletableFuture.supplyAsync(this::veryExpensiveOperations);
    LOGGER.info(httpRequest.getSession().getId() + " : Returning empty response... ");
    return Response.status(HTTP_STATUS_OK).entity(EMPTY_CONTENT).build();
}

// need to do some operations on data from httpRequest
private String veryExpensiveOperations() {
    LOGGER.info(httpRequest.toString());
    LOGGER.info("Start very expensive operations");
    try {
        Thread.sleep(3000);
        LOGGER.info("Finished");
        return "DONE";
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        e.printStackTrace();
        LOGGER.error("Error: " + e.getMessage());
        return "ERROR";
    }
}

}

总而言之,我得到了立即响应,但是VeryExpensiveOperations()方法似乎失去了httpRequest值,这对我来说太糟糕了因为我需要使用来自客户端请求的值调用其他web服务。谢谢你的帮助!

对于我的应用我正在使用Jetty ver。 9.2.18.v20160721

2 个答案:

答案 0 :(得分:3)

完成对servlet的调度后,将提交响应并回收请求和响应对象。

要处理servlet规范,必须使用AsyncContext(通过HttpServletRequest.startAsync()调用获得)让容器知道请求/响应尚未完成,并且处理它是发生在非调度线程中(如CompletableFuture.supplyAsync()调用)

至于如何混合JAX-RS和AsyncContext,我不知道。我甚至不知道JAX-RS是否已经更新以支持AsyncContext

答案 1 :(得分:1)

感谢Joakim的回答(我不能赞成它,因为我在这里很新,我没有足够的声誉)。根据您对gem install rails的了解,我找到了一种快速回复的方法。更改后的代码(适用于runAsync和supplyAsync):

AsyncContext