Playframework Play框架:作业中类似等待的功能

Playframework Play框架:作业中类似等待的功能,playframework,scheduled-tasks,Playframework,Scheduled Tasks,我正在尝试使用正在使用的异步作业运行一个长时间运行的任务(而不阻塞HTTP请求执行池)。 Play中的作业完全由框架管理,因此Play将负责数据库连接和事务。这意味着作业在单个事务中作为普通调用运行。这对于大多数用例来说都很好,但是如果您需要在作业完成之前提交一些数据呢 那么根据,一个选择是, 将流程拆分为几个小作业 他举了以下例子: @On("0 0 12 * * ?") public class UpdateCounters extends Job { public void do

我正在尝试使用正在使用的异步作业运行一个长时间运行的任务(而不阻塞HTTP请求执行池)。 Play中的作业完全由框架管理,因此Play将负责数据库连接和事务。这意味着作业在单个事务中作为普通调用运行。这对于大多数用例来说都很好,但是如果您需要在作业完成之前提交一些数据呢

那么根据,一个选择是,

将流程拆分为几个小作业

他举了以下例子:

@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(); 
       } 
   } 
}
“0 12**”上的
@On
公共类UpdateCounters扩展作业{
public void doJob(){
List employist=Employee.find(“冗长乏味的SQL:)”).fetch();
对于(员工emp:Employist){
新的UpdateEmployeeJob(emp).now().get();
} 
} 
}
这很酷。。。每个新作业都有自己的事务,因此当这个新作业完成时,它会提交数据。干净简单! 但是,如果您不想这样做,该怎么办?假设您需要等待数据提交后才能继续初始作业

通常,您会从新作业中检索承诺并调用await(jobPromise),但这在作业中不起作用(await仅在扩展控制器时可用,并且不会在作业中实现)


那么,在新的较小作业完成之前,暂停初始作业的最佳方式是什么呢?

鉴于游戏的性质,我想说的唯一方式是设置一些标志(通常在数据库中),“父”作业可以在循环中检查并阻止自己等待它

对于exmaple,类似于:

//take it as an idea, not as working code as it may have typos and dragons
public void doJob() { 
       String uuid = generateUUID();
       List<Employee> empList = Employee.find("long and boring SQL :)").fetch(); 
       for(Employee emp : empList) { 
           //update employee giving uuid so we know this job is related to this parent
           new UpdateEmployeeJob(emp, uuid).now().get(); 
       } 
       int done = 0;
       while(done < empList.size()) {
          //query db for number of instances updated with this uuid 
          //(assuming instance updated once child job is done)
          done = Update.count("uuid = ?1",uuid);
       }
   }
//把它当作一个想法,而不是像工作代码那样,因为它可能有打字错误和龙
public void doJob(){
字符串uuid=generateuid();
List employist=Employee.find(“冗长乏味的SQL:)”).fetch();
对于(员工emp:Employist){
//更新提供uuid的员工,以便我们知道此作业与此父项相关
新的UpdateEmployeeJob(emp,uuid).now().get();
} 
int done=0;
while(完成

这可以管理它

在研究了不同的方法来确定任务是否完成(不使用数据库)后,我注意到Play Promise实现了该接口,因此具有isDone()操作,可用于检查任务是否完成

更好的是,接口还定义了一个get()方法

如有必要,等待计算完成,然后检索 它的结果

因此,在新的较小作业完成之前暂停初始作业,可以通过对承诺调用get()来实现,该承诺在对较小作业调用now()时返回(在Guillaume的示例中确实如此)


谢谢

也许您可以使用以下代码执行批提交:


Employee.em().getTransaction().commit();
Employee.em().getTransaction().begin();
Employee.em().flush();
Employee.em().clear();

我明白你的意思。这样做的缺点是等待时不会释放任何资源。事实上,通过检查UUID字段,可以向数据库添加额外的负载。当您调用wait(在控制器中)时,您要求Play在恢复请求之前等待承诺的结果可用。等待时,Play将停止代码,重新使用线程来处理其他请求,并在您等待的承诺值可用时尽快恢复代码”。我想我可以在While循环中添加thread.sleep,以减轻DB的负担,但我希望它更“优雅”“解决方案。我知道,这并不完美,可悲的是,我不确定是否有替代方案。在db负载上,这可以通过缓存进行管理,只需用检查缓存中某个值的方法替换Updated.count(),如果该值不在缓存中,则查询db并将结果存储在缓存中。您可以将缓存中的生存时间设置为1分钟,这样它就不会经常查询。

        Employee.em().getTransaction().commit();
        Employee.em().getTransaction().begin();
        Employee.em().flush();
        Employee.em().clear();