【问题标题】:Run Java EE CDI task with interval以间隔运行 Java EE CDI 任务
【发布时间】:2021-04-15 08:27:11
【问题描述】:

一旦我的应用程序 (WAR) 启动,我需要以间隔运行任务,我使用的是 WildFly 21。 任务应该在启动时初始化,并在某个时间间隔执行一些工作。

类在下面

@ApplicationScoped
@ActivateRequestContext
public class TaskRunner {

 
  @Resource private ManagedScheduledExecutorService scheduler;

  @Inject private ScheduledFuture<?> TaskRunnerScheduler;

  private boolean initialized = false;

  private void init(@Observes @Initialized(ApplicationScoped.class) Object init) {

    if (initialized) return;

   
    initialized = true;
    try {
      // Execute at startup
      TaskRunner = scheduler.schedule(this::runSchedule, getSchedule());
    } catch (Throwable throwable) {

    }
  }

  private void runSchedule() {
//do some work
  }

  private Trigger getSchedule() {
    return new Trigger() {
      @Override
      public Date getNextRunTime(LastExecution lastExecutionInfo, Date taskScheduledTime) {
        return Date.from(
            ZonedDateTime.now().withSecond(0).withNano(0).plusHours("4").toInstant());
      }

      @Override
      public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime) 
       {return false;}};
  }

}

在尝试部署应用程序时,我收到以下错误

 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-6) MSC000001: Failed to start service jboss.deployment.unit."task-web.war".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."task-web.war".WeldStartService: Failed to start service
    at org.jboss.msc@1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1731)
    at org.jboss.msc@1.4.12.Final//org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1559)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type ScheduledFuture<?> with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private TaskRunner.TaskRunnerScheduler
  at TaskRunner.TaskRunnerScheduler(TaskRunner.java:0)

    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:378)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:290)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:143)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:164)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:526)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:64)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:62)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
    at org.jboss.weld.core@3.1.5.Final//org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.JBossThread.run(JBossThread.java:513)

任何想法是什么原因导致此错误?

【问题讨论】:

    标签: wildfly cdi java-ee-8


    【解决方案1】:

    您似乎希望每 4 小时左右运行一次。我可以建议更清洁的实现吗?

    @Startup
    @Singleton
    public class MyScheduler {
        @PostConstruct
        private void runAtStartup() {
            // whatever makes sense here
        }
    
        @Schedule(hour = "*/4", persistent = false )
        private void runSomething() {
            // something here
        }
    }
    

    这会设置一个在启动时运行的 EJB (@Startup),表示它只有一个实例 (@Singleton)。然后它每 4 小时运行一次runSomething() 方法。您可以查看Schedule Javadocs,因为还有许多其他方法可以运行它。如果 @PostConstruct 方法以前仅用于设置计时器,您可能需要也可能不需要。

    persistent 参数告诉 Wildfly 记住上次运行的时间,如果重新启动,则继续按该计划运行。如果您不关心您的方法是否在重新启动时再次运行,请将此设置为 false。

    我唯一的警告是这种机制不处理重叠。如果您使用此方法并在最后一个方法完成之前运行新的调度方法(在本例中为 4 小时后),则至少会导致日志中出现错误,并且调度不会按您期望的方式运行。

    【讨论】:

    • 感谢您的帖子,但我必须只使用 CDI bean 而不是 EJB
    • CDI 与 EJB 属于同一规范的一部分,并且包含在 Wildfly 中——这是我一段时间以来听到的最糟糕的要求。
    • 不是,但我们只需要使用 CDI 进行开发
    【解决方案2】:

    仅从您的代码 sn-p 中,只需删除(未使用的)TaskRunnerScheduler 字段。

    【讨论】:

      【解决方案3】:

      我发现了问题,是下面一行的错字

       @Inject private ScheduledFuture<?> TaskRunnerScheduler;
      

      正确的是没有注入

       private ScheduledFuture<?> TaskRunnerScheduler;
      

      【讨论】:

        猜你喜欢
        • 2015-08-01
        • 1970-01-01
        • 2012-01-19
        • 2011-10-15
        • 2015-07-29
        • 1970-01-01
        • 1970-01-01
        • 2017-02-22
        • 2010-11-05
        相关资源
        最近更新 更多