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;

然后你可以完全删除 onCreateonDestroy 方法,因为服务器管理注入的执行程序。