ManagedScheduledExecutorService 无法 运行 计划任务,因为容器已挂起
ManagedScheduledExecutorService Cannot run scheduled task as container is suspended
我在 WAR 应用程序中将 ManagedScheduledExecutorService
传递给外部库。我在 @ApplicationScoped CDI bean 中初始化上下文时调用的方法中执行此操作:
public void init( @Observes @Initialized( ApplicationScoped.class ) Object aInit )
{
//pass ManagedScheduledExecutorService to library
//initialize library
}
我得到以下异常:
13:08:23,639 ERROR [org.jboss.as.ee] (EE-ManagedScheduledExecutorService-default-Thread-2) WFLYEE0110: Failed to run scheduled task: java.lang.IllegalStateException: WFLYEE0111: Cannot run scheduled task org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl$ActualScheduledPinger@4cb08cda as container is suspended
at org.jboss.as.ee@21.0.1-2-PSI//org.jboss.as.ee.concurrent.ControlPointUtils$ControlledScheduledRunnable.run(ControlPointUtils.java:184)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at org.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.access1(ManagedScheduledThreadPoolExecutor.java:360)
at org.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.run(ManagedScheduledThreadPoolExecutor.java:511)
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.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:227)
我看到了 问题,但我对答案不满意。我使用外部库(artemis 客户端),我无法直接控制它何时安排第一个任务。我不想修改这个库。我不能为它使用 javax.ejb.TimerService
,我只能将 ScheduledExecutorService
传递给它。我可以延迟这个库的初始化,但我不想猜测什么延迟是足够和安全的。如何解决这个问题?
我不确定我是否正确理解了 问题的答案。我理解这个答案,而不是直接使用 ManagedScheduledExecutorService
我应该使用 javax.ejb.TimerService
但我只将 ManagedScheduledExecutorService
传递给外部库所以我不能使用 javax.ejb.TimerService
或 javax.ejb.Schedule
注释在这个外部库中。
我通过使用 javax.ejb.TimerService
初始化外部库解决了我的问题。
我这样做了:
@Singleton
@Startup
public class AppEJB
{
@Resource
private TimerService timerSvc;
@Resource( name = "DefaultManagedScheduledExecutorService" )
private ManagedScheduledExecutorService scheduledExecutorService;
@PostConstruct
private void postConstruct( )
{
final ScheduledFuture< Integer > schedule =
scheduledExecutorService.schedule( () -> 1, 1, TimeUnit.MILLISECONDS );
try
{
schedule.get();
}
catch( Exception aE )
{
log.warn("Container is not ready to start my library. It will be started later.");
timerService.createSingleActionTimer( 1, new TimerConfig() );
return;
}
startLib();
}
@Timeout
private void startLibAfterTimeout()
{
startLib();
}
private void startLib()
{
//pass ManagedScheduledExecutorService to library
//initialize library
}
}
这个解决方案有一些缺点。如果应用程序部署在启动的 Wildfly 上,则库会在部署期间初始化。不幸的是,如果 Wildfly 在 wildfly 重启后启动,则在部署后(Wildfly 完成启动后)执行初始化。这意味着在重启 Wildfly 之后我仍然需要等待我的外部库初始化。它会对集成测试产生影响。 Arquillian 部署在启动的 Wildfly 上,因此检查预定的执行程序服务是否可用可以避免睡眠或类似 Arquillian 集成测试中的事情。
我尝试了以下解决方案,但它不起作用。部署应用程序永远不会结束,因为 while 循环永远不会结束。
@ApplicationScoped
public class AppBean
{
@Resource( name = "DefaultManagedScheduledExecutorService" )
private ManagedScheduledExecutorService scheduledExecutorService;
public void init( @Observes @Initialized( ApplicationScoped.class ) Object aInit )
{
//IT NOT WORK!!!
System.out.println( "init" );
while( true )
{
try
{
final ScheduledFuture< Integer > schedule =
scheduledExecutorService.schedule( () -> { return 1; }, 0, TimeUnit.MILLISECONDS );
final Integer integer = schedule.get();
break;
}
catch( InterruptedException aE )
{
System.out.println( "interrupted" );
}
catch( ExecutionException aE )
{
System.out.println( "exception, sleep" );
try
{
Thread.sleep( 2000 );
}
catch( InterruptedException aInterruptedException )
{
aInterruptedException.printStackTrace();
}
}
}
//pass ManagedScheduledExecutorService to library
//initialize library
}
我在 WAR 应用程序中将 ManagedScheduledExecutorService
传递给外部库。我在 @ApplicationScoped CDI bean 中初始化上下文时调用的方法中执行此操作:
public void init( @Observes @Initialized( ApplicationScoped.class ) Object aInit )
{
//pass ManagedScheduledExecutorService to library
//initialize library
}
我得到以下异常:
13:08:23,639 ERROR [org.jboss.as.ee] (EE-ManagedScheduledExecutorService-default-Thread-2) WFLYEE0110: Failed to run scheduled task: java.lang.IllegalStateException: WFLYEE0111: Cannot run scheduled task org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl$ActualScheduledPinger@4cb08cda as container is suspended
at org.jboss.as.ee@21.0.1-2-PSI//org.jboss.as.ee.concurrent.ControlPointUtils$ControlledScheduledRunnable.run(ControlPointUtils.java:184)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at org.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.access1(ManagedScheduledThreadPoolExecutor.java:360)
at org.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.run(ManagedScheduledThreadPoolExecutor.java:511)
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.glassfish.javax.enterprise.concurrent//org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:227)
我看到了 javax.ejb.TimerService
,我只能将 ScheduledExecutorService
传递给它。我可以延迟这个库的初始化,但我不想猜测什么延迟是足够和安全的。如何解决这个问题?
我不确定我是否正确理解了 ManagedScheduledExecutorService
我应该使用 javax.ejb.TimerService
但我只将 ManagedScheduledExecutorService
传递给外部库所以我不能使用 javax.ejb.TimerService
或 javax.ejb.Schedule
注释在这个外部库中。
我通过使用 javax.ejb.TimerService
初始化外部库解决了我的问题。
我这样做了:
@Singleton
@Startup
public class AppEJB
{
@Resource
private TimerService timerSvc;
@Resource( name = "DefaultManagedScheduledExecutorService" )
private ManagedScheduledExecutorService scheduledExecutorService;
@PostConstruct
private void postConstruct( )
{
final ScheduledFuture< Integer > schedule =
scheduledExecutorService.schedule( () -> 1, 1, TimeUnit.MILLISECONDS );
try
{
schedule.get();
}
catch( Exception aE )
{
log.warn("Container is not ready to start my library. It will be started later.");
timerService.createSingleActionTimer( 1, new TimerConfig() );
return;
}
startLib();
}
@Timeout
private void startLibAfterTimeout()
{
startLib();
}
private void startLib()
{
//pass ManagedScheduledExecutorService to library
//initialize library
}
}
这个解决方案有一些缺点。如果应用程序部署在启动的 Wildfly 上,则库会在部署期间初始化。不幸的是,如果 Wildfly 在 wildfly 重启后启动,则在部署后(Wildfly 完成启动后)执行初始化。这意味着在重启 Wildfly 之后我仍然需要等待我的外部库初始化。它会对集成测试产生影响。 Arquillian 部署在启动的 Wildfly 上,因此检查预定的执行程序服务是否可用可以避免睡眠或类似 Arquillian 集成测试中的事情。
我尝试了以下解决方案,但它不起作用。部署应用程序永远不会结束,因为 while 循环永远不会结束。
@ApplicationScoped
public class AppBean
{
@Resource( name = "DefaultManagedScheduledExecutorService" )
private ManagedScheduledExecutorService scheduledExecutorService;
public void init( @Observes @Initialized( ApplicationScoped.class ) Object aInit )
{
//IT NOT WORK!!!
System.out.println( "init" );
while( true )
{
try
{
final ScheduledFuture< Integer > schedule =
scheduledExecutorService.schedule( () -> { return 1; }, 0, TimeUnit.MILLISECONDS );
final Integer integer = schedule.get();
break;
}
catch( InterruptedException aE )
{
System.out.println( "interrupted" );
}
catch( ExecutionException aE )
{
System.out.println( "exception, sleep" );
try
{
Thread.sleep( 2000 );
}
catch( InterruptedException aInterruptedException )
{
aInterruptedException.printStackTrace();
}
}
}
//pass ManagedScheduledExecutorService to library
//initialize library
}