休息方法需要很长时间
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;
}
从概念上讲,服务必须有一种方式将故障传达给客户端。有多种方法可以做到这一点。以下是三个示例:
- 客户端调用服务后,服务立即returns一个作业ID。客户端稍后可以使用作业 ID 查询服务的状态(包括错误)。例如,当您在 AWS EC2 上启动实例时,EC2 需要一段时间来为请求提供服务,因此启动请求 returns 一个所谓的 "reservation ID" 您可以在后续操作中使用(如查询状态、终止启动等)。
- 专业:适用于多种情况,并且易于实施。
- 缺点: 需要轮询。 (即更健谈。)
- 客户端提供服务在作业完成时调用的回调 URI。回调 URI 可以配置到服务中,也可以作为请求参数传递。 (不要在服务中硬编码回调 URI,因为服务不应该依赖于它们的客户端。)
- 亲:还是很简单的,避免轮询。
- 缺点:客户端必须有服务调用的URI,这可能不方便。 (例如,客户端可能是桌面应用程序而不是服务,防火墙可能会阻止它等)
- 客户端将通知推送到消息队列中,然后客户端监听该队列。
- 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();
}
这可以给你一个思路。记得清除地图上的旧任务。
这是一个设计题,我想请教一些想法。 我有一个休息方法,它会触发长时间任务(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;
}
从概念上讲,服务必须有一种方式将故障传达给客户端。有多种方法可以做到这一点。以下是三个示例:
- 客户端调用服务后,服务立即returns一个作业ID。客户端稍后可以使用作业 ID 查询服务的状态(包括错误)。例如,当您在 AWS EC2 上启动实例时,EC2 需要一段时间来为请求提供服务,因此启动请求 returns 一个所谓的 "reservation ID" 您可以在后续操作中使用(如查询状态、终止启动等)。
- 专业:适用于多种情况,并且易于实施。
- 缺点: 需要轮询。 (即更健谈。)
- 客户端提供服务在作业完成时调用的回调 URI。回调 URI 可以配置到服务中,也可以作为请求参数传递。 (不要在服务中硬编码回调 URI,因为服务不应该依赖于它们的客户端。)
- 亲:还是很简单的,避免轮询。
- 缺点:客户端必须有服务调用的URI,这可能不方便。 (例如,客户端可能是桌面应用程序而不是服务,防火墙可能会阻止它等)
- 客户端将通知推送到消息队列中,然后客户端监听该队列。
- 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();
}
这可以给你一个思路。记得清除地图上的旧任务。