【发布时间】:2014-12-18 14:51:49
【问题描述】:
请考虑以下场景:
1) 一个 Singleton SchedulerService 管理/创建一堆JobQueues
@Startup
@Singleton
public class SchedulerService
{
@Inject
private Instance<JobQueue> jobQueueInstance;
...
public JobQueue addQueue(String name)
{
JobQueue q = jobQueueInstance.get();
....
return q;
}
}
2) 可能有几个JobQueues,他们各自管理/启动/跟进他们正在运行/待定的工作:
public class JobQueue implements SchedulerListener
{
@PersistenceContext(unitName = "...")
private EntityManager entityManager;
public void addJob(Job newJob)
{
.... entityManager.persist(newJob); ....
newJob.addSchedulerListener(this);
}
...
public void deleteJob(Job j)
{
.... entityManager.delete(j); ....
}
// part of SchedulerListener, invoked from Job's Thread
@Override
public void taskSucceeded(Job job)
{
deleteJob(job);
}
// part of SchedulerListener, invoked from Job's Thread
@Override
public void taskFailed(Job job)
{
deleteJob(job);
}
}
一切运行良好,entityManager 被正确地 @Injected,当从其他托管 bean 调用 addJob() 和 deleteJob() 时,实体被正确地持久化/删除。
现在,对于实际的作业执行,我使用的是不支持 CDI 的 Cron4j。
它启动新线程并在该线程中运行实际作业。
当作业结束时,它会通过taskSucceeded/taskFailed 方法通知我的 JobQueue(监听作业终止事件)。
因为这些taskSucceeded/taskFailed 方法是从作业线程(不是“容器管理”的)调用的,所以我可以理解地得到以下异常:
4:46:27,032 ERROR [cob.scheduler.service.JobQueue] (cron4j::scheduler[DEFAULT]::task[442]) Job xxx failed: javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:869) [wildfly-jpa-9.0.0.Alpha1.jar:9.0.0.Alpha1]
at org.jboss.as.jpa.container.AbstractEntityManager.merge(AbstractEntityManager.java:567) [wildfly-jpa-9.0.0.Alpha1.jar:9.0.0.Alpha1]
at cob.scheduler.service.JobQueue.deleteJob(JobQueue.java:287) [classes:]
at cob.scheduler.service.JobQueue.deleteAndAdvance(JobQueue.java:241) [classes:]
at cob.scheduler.service.JobQueue.taskSucceeded(JobQueue.java:226) [classes:]
at it.sauronsoftware.cron4j.Scheduler.notifyTaskSucceeded(Scheduler.java:724) [classes:]
at it.sauronsoftware.cron4j.TaskExecutor$Runner.run(TaskExecutor.java:500) [classes:]
at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_45]
我想知道什么是继续的好方法。基本上我需要以某种方式“回到 EE 容器”,即从 EE 领域之外调用容器管理的方法。
我已阅读有关 ManagedExecutorService 的信息,但我不确定这是否适用或如何使用它。
我还尝试@Inject private JobQueue self; 并调用self.deleteJob() 而不仅仅是this.deleteJob(),但这会在部署时生成以下异常:
org.jboss.weld.exceptions.DeploymentException: WELD-001443: Pseudo scoped bean has circular dependencies. Dependency path:
- Managed Bean [class cob.scheduler.service.JobQueue] with qualifiers [@Any @Default],
- [BackedAnnotatedField] @Inject private cob.scheduler.service.JobQueue.self,
- Managed Bean [class cob.scheduler.service.JobQueue] with qualifiers [@Any @Default]
at org.jboss.weld.bootstrap.Validator.reallyValidatePseudoScopedBean(Validator.java:904)
at org.jboss.weld.bootstrap.Validator.validatePseudoScopedInjectionPoint(Validator.java:946)
at org.jboss.weld.bootstrap.Validator.reallyValidatePseudoScopedBean(Validator.java:913)
at org.jboss.weld.bootstrap.Validator.validatePseudoScopedBean(Validator.java:890)
at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:148)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:165)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:529)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
at java.util.concurrent.FutureTask.run(FutureTask.java:262) [rt.jar:1.7.0_45]
... 3 more
注意:除了“资源本地”事务管理,我一切正常。我认为将其转换为 JTA 会很容易,但是唉。
任何指针将不胜感激。
【问题讨论】:
标签: jakarta-ee managed-bean java-ee-7