I've got this project I'm working on which requires a lot of processing and time and I wish to start the process with an API call to a backend.
Right now I have Jersey and Jackson with Maven in a development environment using Payara as the server.
I'm trying to make it so that the user can just press 'start' in a web interface to start the processing of the long task in the background and JSON requests can just fetch status updates until the task is finished.
Here is my (pretty awful) test code that I'm using to try and get an idea of the process. It doesn't matter too much if the task is shared between all users or not as the project is just a prototype.
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();
}
Here's something you could try:
@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";
}
}