Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play Framework: await-like functionality in Jobs

I am trying to run a long-running task (without blocking the HTTP request execution pool) using the Asynchronous Jobs in Play. Jobs in Play are fully managed by the framework so Play will take care of the database connections and transactions. This means that a job runs as a plain invocation within a single transaction. This is great for most use-cases but what if you need to commit some data before the job finishes?

Well, according to Guillaume Bort, one option would be

to split your process into several small jobs

He gives the following example:

@On("0 0 12 * * ?") 
public class UpdateCounters extends Job { 
   public void doJob() { 
       List<Employee> empList = Employee.find("long and boring SQL :)").fetch(); 
       for(Employee emp : empList) { 
           new UpdateEmployeeJob(emp).now().get(); 
       } 
   } 
}

This is cool... Each new job will have it's own transaction so when this new job finishes, it commits that data. Clean and simple! But what if you don't want to do this asynchronous? Say you need to wait until the data is committed before you continue with the initial job?

Normally, you would retrieve the Promise from the new Job and call await(jobPromise) but this will not work in a Job (await is only available when extending Controller and is not implemented on Job)...

So what would be the best way to pause the initial job until the new smaller job completes?

like image 950
stikkos Avatar asked Oct 19 '11 16:10

stikkos


1 Answers

After looking into different ways of finding out if a Job was done (without using a database), I noticed that a Play Promise implements the Future interface and thus has the isDone() operation which can be used this to check if the task completed.

Even better, the Future interface also defines a get() method which

waits if necessary for the computation to complete, and then retrieves its result.

So pausing the initial job until the new smaller job completes, can be achieved by calling get() on the Promise, returned when calling now() on the smaller job (as indeed done in Guillaume's example)

Thanks!

like image 116
stikkos Avatar answered Oct 26 '22 18:10

stikkos