我将ManagedScheduledExecutorService
传递给WAR应用程序中的外部库。我在@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.access$201(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)
我看到如何延迟ManagedScheduledExecutorService,直到容器不挂起?问题,但我对答案不满意。我使用外部库(artemis客户机),我无法直接控制它何时调度第一个任务。我不想修改这个库。我不能用javax.ejb.TimerService
,我只能把ScheduledExecutorService
传递给它。我可以延迟这个库的初始化,但我不想猜测什么延迟是足够和安全的。如何解决这个问题?
我不确定如果我正确理解从如何延迟ManagedScheduledExecutorService的答案,直到容器不挂起?的问题。我理解这个答案,而不是直接使用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
}