Java jersey glassfish (payara) 休息:在 运行 异步方法上获取状态
Java jersey glassfish (payara) rest: get status on running async method
我正在处理这个项目,它需要大量的处理和时间,我希望通过 API 调用后端来开始这个过程。
现在我在使用 Payara 作为服务器的开发环境中使用 Jersey 和 Jackson 以及 Maven。
我正在尝试做到这一点,以便用户只需在 Web 界面中按 'start' 即可开始在后台处理长任务,而 JSON 请求只能获取状态更新直到任务完成。
这是我用来尝试了解流程的(非常糟糕的)测试代码。该任务是否由所有用户共享并不重要,因为该项目只是一个原型。
ExecutorService task = Executors
.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("long-running-resource-executor-%d")
.setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler()).build());
AsyncResponse asyncBla;
@GET
@Path("/expensive")
public void getExpensive(@Suspended final AsyncResponse async) {
asyncBla = async;
task.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
System.out.println("Ba-boop");
} catch (InterruptedException e) {
System.out.println("barp");
}
// async.resume("Started");
}
});
async.resume("Started");
}
@GET
@Path("/expensive/status")
public String getExpensiveStatus() {
if (asyncBla == null)
return "Nope.";
return asyncBla.isDone();
}
您可以尝试以下方法:
@Singleton
@Path("expensive-task")
public class ExpensiveTaskResource {
private ExecutorService executor;
private Future<String> futureResult;
@PostConstruct
public void onCreate() {
this.executor = Executors.newSingleThreadExecutor();
}
@POST
public Response startTask() {
futureResult = executor.submit(new ExpensiveTask());
return Response.status(Status.ACCEPTED).build();
}
@GET
public Response getResult() throws ExecutionException, InterruptedException {
if (futureResult != null && futureResult.isDone()) {
return Response.status(Status.OK).entity(futureResult.get()).build();
} else {
return Response.status(Status.FORBIDDEN).entity("Try later").build();
}
}
@PreDestroy
public void onDestroy() {
this.executor.shutdownNow();
}
}
public class ExpensiveTask implements Callable<String> {
@Override
public String call() throws Exception {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task completed";
}
}
为了补充 Cassio 的答案,最好使用注入的执行程序服务而不是 Executors.newSingleThreadExecutor()
。这减少了代码量,但更重要的是,它将 运行 托管线程中的任务可以访问服务器的上下文和资源。
就这么简单:
@Singleton
@Path("expensive-task")
public class ExpensiveTaskResource {
@Inject
private ManagedExecutorService executor;
然后你可以完全删除 onCreate
和 onDestroy
方法,因为服务器管理注入的执行程序。
我正在处理这个项目,它需要大量的处理和时间,我希望通过 API 调用后端来开始这个过程。
现在我在使用 Payara 作为服务器的开发环境中使用 Jersey 和 Jackson 以及 Maven。
我正在尝试做到这一点,以便用户只需在 Web 界面中按 'start' 即可开始在后台处理长任务,而 JSON 请求只能获取状态更新直到任务完成。
这是我用来尝试了解流程的(非常糟糕的)测试代码。该任务是否由所有用户共享并不重要,因为该项目只是一个原型。
ExecutorService task = Executors
.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("long-running-resource-executor-%d")
.setUncaughtExceptionHandler(new JerseyProcessingUncaughtExceptionHandler()).build());
AsyncResponse asyncBla;
@GET
@Path("/expensive")
public void getExpensive(@Suspended final AsyncResponse async) {
asyncBla = async;
task.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
System.out.println("Ba-boop");
} catch (InterruptedException e) {
System.out.println("barp");
}
// async.resume("Started");
}
});
async.resume("Started");
}
@GET
@Path("/expensive/status")
public String getExpensiveStatus() {
if (asyncBla == null)
return "Nope.";
return asyncBla.isDone();
}
您可以尝试以下方法:
@Singleton
@Path("expensive-task")
public class ExpensiveTaskResource {
private ExecutorService executor;
private Future<String> futureResult;
@PostConstruct
public void onCreate() {
this.executor = Executors.newSingleThreadExecutor();
}
@POST
public Response startTask() {
futureResult = executor.submit(new ExpensiveTask());
return Response.status(Status.ACCEPTED).build();
}
@GET
public Response getResult() throws ExecutionException, InterruptedException {
if (futureResult != null && futureResult.isDone()) {
return Response.status(Status.OK).entity(futureResult.get()).build();
} else {
return Response.status(Status.FORBIDDEN).entity("Try later").build();
}
}
@PreDestroy
public void onDestroy() {
this.executor.shutdownNow();
}
}
public class ExpensiveTask implements Callable<String> {
@Override
public String call() throws Exception {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Task completed";
}
}
为了补充 Cassio 的答案,最好使用注入的执行程序服务而不是 Executors.newSingleThreadExecutor()
。这减少了代码量,但更重要的是,它将 运行 托管线程中的任务可以访问服务器的上下文和资源。
就这么简单:
@Singleton
@Path("expensive-task")
public class ExpensiveTaskResource {
@Inject
private ManagedExecutorService executor;
然后你可以完全删除 onCreate
和 onDestroy
方法,因为服务器管理注入的执行程序。