Spring 非阻塞端点:向调用者返回操作ID-想了解您对我的实现的看法吗?

Spring 非阻塞端点:向调用者返回操作ID-想了解您对我的实现的看法吗?,spring,spring-boot,Spring,Spring Boot,靴子专家 我最近开始在SpringBoot中编程,我偶然发现了一个问题,我想听听你们的意见 我努力实现的目标: 我创建了一个公开GET端点的控制器,名为nonBlockingEndpoint。此nonBlockingEndpoint执行一个相当长的操作,该操作占用大量资源,可以运行20到40秒。(在附加的代码中,它被线程.sleep()模拟。) 无论何时调用nonBlockingEndpoint,spring应用程序都应该注册该调用,并立即向调用者返回操作ID 然后,调用方可以使用此ID在另一

靴子专家

我最近开始在SpringBoot中编程,我偶然发现了一个问题,我想听听你们的意见

我努力实现的目标:

  • 我创建了一个公开
    GET
    端点的控制器,名为
    nonBlockingEndpoint
    。此
    nonBlockingEndpoint
    执行一个相当长的操作,该操作占用大量资源,可以运行20到40秒。(在附加的代码中,它被
    线程.sleep()模拟。
  • 无论何时调用
    nonBlockingEndpoint
    ,spring应用程序都应该注册该调用,并立即向调用者返回操作ID
  • 然后,调用方可以使用此ID在另一个端点上查询此操作的状态。开始时,它将启动,一旦控制器完成重新测试,它将被转换为一个代码,如
    SERVICE\u OK
    。然后,调用方知道他的请求已在服务器上成功完成
我找到的解决方案:

  • 我有以下控制器(请注意,它明确地不是标记为@Async)
  • 它使用
    APIOperationsManager
    注册新操作已启动
  • 我使用
    CompletableFuture
    java构造,通过使用
    CompletableFuture.supplyAsync(()->{}
  • 我立即向调用方返回响应,告知操作正在进行
  • 异步任务完成后,我使用
    cf.thenRun()
    通过API操作管理器更新操作状态
代码如下:

    @GetMapping(path="/nonBlockingEndpoint")
public @ResponseBody ResponseOperation nonBlocking() {

    // Register a new operation
    APIOperationsManager apiOpsManager = APIOperationsManager.getInstance();
    final int operationID = apiOpsManager.registerNewOperation(Constants.OpStatus.PROCESSING);
    ResponseOperation response = new ResponseOperation();

    response.setMessage("Triggered non-blocking call, use the operation id to check status");
    response.setOperationID(operationID);
    response.setOpRes(Constants.OpStatus.PROCESSING);

    CompletableFuture<Boolean> cf = CompletableFuture.supplyAsync(() -> {

        try {
            // Here we will 
            Thread.sleep(10000L);
        } catch (InterruptedException e) {}

        // whatever the return value was
        return true;
    });
    cf.thenRun(() ->{ 
        // We are done with the super long process, so update our Operations Manager
        APIOperationsManager a = APIOperationsManager.getInstance();
        boolean asyncSuccess = false;

        try {asyncSuccess = cf.get();} 
        catch (Exception e) {}

        if(true == asyncSuccess) {
            a.updateOperationStatus(operationID, Constants.OpStatus.OK);
            a.updateOperationMessage(operationID, "success: The long running process has finished and this is your result: SOME RESULT" );
        } 
        else {
            a.updateOperationStatus(operationID, Constants.OpStatus.INTERNAL_ERROR);
            a.updateOperationMessage(operationID, "error: The long running process has failed."); 
        }
    });

    return response;
}
@GetMapping(path=“/nonBlockingEndpoint”)
public@ResponseBody ResponseOperation非阻塞(){
//注册新操作
APIOperationsManager apiOpsManager=APIOperationsManager.getInstance();
final int operationID=apiOpsManager.registerNewOperation(Constants.OpStatus.PROCESSING);
ResponseOperation response=新的ResponseOperation();
response.setMessage(“触发非阻塞调用,使用操作id检查状态”);
响应。设置操作ID(操作ID);
response.setOpRes(Constants.OpStatus.PROCESSING);
CompletableFuture cf=CompletableFuture.SupplySync(()->{
试一试{
//我们会的
线程。睡眠(10000L);
}捕获(中断异常e){}
//不管返回值是多少
返回true;
});
cf.thenRun(()->{
//我们已经完成了超长流程,请更新我们的运营经理
APIOperationsManager a=APIOperationsManager.getInstance();
布尔asyncSuccess=false;
尝试{asyncSuccess=cf.get();}
捕获(例外e){}
if(true==asyncSuccess){
a、 updateOperationStatus(operationID,Constants.OpStatus.OK);
a、 updateOperationMessage(operationID,“成功:长时间运行的流程已完成,这是您的结果:某些结果”);
} 
否则{
a、 updateOperationStatus(operationID,Constants.OpStatus.INTERNAL_ERROR);
a、 updateOperationMessage(operationID,“错误:长时间运行的进程失败”);
}
});
返回响应;
}
以下是完整性的APIOperationsManager.java:

public class APIOperationsManager {

    private static APIOperationsManager instance = null;

    private Vector<Operation> operations;
    private int currentOperationId;

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    protected APIOperationsManager() {}

    public static APIOperationsManager getInstance() {
        if(instance == null) {
            synchronized(APIOperationsManager.class) {
                if(instance == null) {
                    instance = new APIOperationsManager();
                    instance.operations = new Vector<Operation>();
                    instance.currentOperationId = 1;
                }
            }
        }
        return instance;
    }


    public synchronized int registerNewOperation(OpStatus status) {
        cleanOperationsList();

        currentOperationId = currentOperationId + 1;
        Operation newOperation = new Operation(currentOperationId, status);
        operations.add(newOperation);
        log.info("Registered new Operation to watch: " + newOperation.toString());
        return newOperation.getId();
    }

    public synchronized Operation getOperation(int id) {

        for(Iterator<Operation> iterator = operations.iterator(); iterator.hasNext();) {
            Operation op = iterator.next();
            if(op.getId() == id) {
                return op;
            }
        }

        Operation notFound = new Operation(-1, OpStatus.INTERNAL_ERROR);
        notFound.setCrated(null);

        return notFound;
    }

    public synchronized void updateOperationStatus (int id, OpStatus newStatus) {

        iteration : for(Iterator<Operation> iterator = operations.iterator(); iterator.hasNext();) {
            Operation op = iterator.next();
            if(op.getId() == id) {
                op.setStatus(newStatus);
                log.info("Updated Operation status: " + op.toString());
                break iteration;
            }
        }
    }

    public synchronized void updateOperationMessage (int id, String message) {

        iteration : for(Iterator<Operation> iterator = operations.iterator(); iterator.hasNext();) {
            Operation op = iterator.next();
            if(op.getId() == id) {
                op.setMessage(message);
                log.info("Updated Operation status: " + op.toString());
                break iteration;
            }
        }
    }

    private synchronized void cleanOperationsList() {
        Date now = new Date();

        for(Iterator<Operation> iterator = operations.iterator(); iterator.hasNext();) {
            Operation op = iterator.next();
            if((now.getTime() - op.getCrated().getTime()) >= Constants.MIN_HOLD_DURATION_OPERATIONS ) {
                log.info("Removed operation from watchlist: " + op.toString());
                iterator.remove();
            }
        }
    }
}
公共类APIOperationsManager{
私有静态APIOperationsManager实例=null;
私人病媒业务;
私有int currentOperationId;
私有静态最终记录器log=LoggerFactory.getLogger(Application.class);
受保护的APIOperationsManager(){}
公共静态APIOperationsManager getInstance(){
if(实例==null){
已同步(APIOperationsManager.class){
if(实例==null){
实例=新的APIOperationsManager();
instance.operations=新向量();
instance.currentOperationId=1;
}
}
}
返回实例;
}
公共同步int寄存器WO操作(OpStatus状态){
cleanOperationsList();
currentOperationId=currentOperationId+1;
操作newOperation=新操作(currentOperationId,状态);
操作。添加(新建操作);
log.info(“要监视的已注册新操作:+newOperation.toString());
返回newOperation.getId();
}
公共同步操作getOperation(int id){
for(Iterator Iterator=operations.Iterator();Iterator.hasNext();){
操作op=iterator.next();
if(op.getId()==id){
返回op;
}
}
操作未找到=新操作(-1,操作状态。内部错误);
未找到。设置板条箱(空);
返回未找到;
}
公共同步的void updateOperationStatus(int-id,optstatus-newStatus){
迭代:for(Iterator Iterator=operations.Iterator();Iterator.hasNext();){
操作op=iterator.next();
if(op.getId()==id){
op.setStatus(newStatus);
log.info(“更新的操作状态:+op.toString());
中断迭代;
}
}
}
公共同步的void updateOperationMessage(int-id,字符串消息){
迭代:for(Iterator Iterator=operations.Iterator();Iterator.hasNext();){
操作op=iterator.next();
if(op.getId()==id){
op.setMessage(消息);
log.info(“更新的操作状态:+op.toString());
中断迭代;
}
}
}
私有同步的void cleanOperationsList(){
现在日期=新日期();
用于(Itera)