休息方法需要很长时间

Rest method need long time

这是一个设计题,我想请教一些想法。 我有一个休息方法,它会触发长时间任务(10~15分钟) 由于该功能需要很长时间,我 运行 它作为一个线程, 这样可以避免方法超时,但是我怎么知道线程是否出错

Runnable loader = new Runnable() {
        public void run() {
            //tasks
        }
    };

 (new Thread(loader)).start();

更新:其余服务如下

@path()
beginload(){
     //let thread run and return info first
     //how can i know if this thread went wrong?
     (new Thread(loader)).start();
     return "need 15 minutes";        
}

如果您想获取线程的 return 值和 throw/catch 可能的异常,请考虑使用提供更多功能的 Callable rather than Runnable, and it can be used along with ExecutorService

Callable : A task that returns a result and may throw an exception.
Implementors define a single method with no arguments called call.

public interface Callable<V> {
    V call() throws Exception;
}

从概念上讲,服务必须有一种方式将故障传达给客户端。有多种方法可以做到这一点。以下是三个示例:

  1. 客户端调用服务后,服务立即returns一个作业ID。客户端稍后可以使用作业 ID 查询服务的状态(包括错误)。例如,当您在 AWS EC2 上启动实例时,EC2 需要一段时间来为请求提供服务,因此启动请求 returns 一个所谓的 "reservation ID" 您可以在后续操作中使用(如查询状态、终止启动等)。
    • 专业:适用于多种情况,并且易于实施。
    • 缺点: 需要轮询。 (即更健谈。)
  2. 客户端提供服务在作业完成时调用的回调 URI。回调 URI 可以配置到服务中,也可以作为请求参数传递。 (不要在服务中硬编码回调 URI,因为服务不应该依赖于它们的客户端。)
    • 亲:还是很简单的,避免轮询。
    • 缺点:客户端必须有服务调用的URI,这可能不方便。 (例如,客户端可能是桌面应用程序而不是服务,防火墙可能会阻止它等)
  3. 客户端将通知推送到消息队列中,然后客户端监听该队列。
    • Pro:避免轮询,客户端不需要端点来调用。
    • 缺点:设置更多工作(需要消息传递基础结构)。

还有其他可能性,但这些都是典型的方法。

需要区分不同的请求吗?如果要执行多个任务,则需要一个 ID。

您可以执行以下操作:

private static final ExecutorService es = Executors.newFixedThreadPool(10);
private static final Map<Long, Future<Void>> map = new HashMap<>();

@GET
@Path("/submit")
public Response submitTask() {
    long id = System.currentTimeMillis();
    Future<Void> future = es.submit(new Callable<Void>() {
        public Void call() throws Exception {
            // long task
            // you must throw exception for bad task
            return null;
        }
    });
    map.put(id, future);
    return Response.ok(id, MediaType.TEXT_PLAIN).build();
}

@GET
@Path("/status/{id}")
public Response submitTask(@PathParam("id") long id) {
    Future<Void> future = map.get(id);
    if (future.isDone()) {
        try {
            future.get();
            return Response.ok("Successful!", MediaType.TEXT_PLAIN).build();
        } catch (InterruptedException | ExecutionException e) {
            // log
            return Response.ok("Bad task!", MediaType.TEXT_PLAIN).build();
        }
    }
    return Response.ok("Wait a few seconds.", MediaType.TEXT_PLAIN).build();

}

这可以给你一个思路。记得清除地图上的旧任务。