1

I pass ManagedScheduledExecutorService to external library in my WAR application. I do it in method called when context is initialized inside @ApplicationScoped CDI bean:

public void init( @Observes @Initialized( ApplicationScoped.class ) Object aInit )
{
   //pass ManagedScheduledExecutorService to library
   //initialize library
}

I get following exception:

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)

I saw How to delay ManagedScheduledExecutorService until container is not suspended? question but I am not satisfied with the answer. I use external library (artemis client) and I have no direct control over when it schedules the first task. I do not want to modify this library. I cannot use javax.ejb.TimerService for it, I can only pass ScheduledExecutorService to it. I can delay initialization of this library but I don't want to guess what delay is sufficient and safe. How to solve this issue?

Mariusz
  • 1,907
  • 3
  • 24
  • 39

1 Answers1

0

I am not sure If I correctly understood answer from How to delay ManagedScheduledExecutorService until container is not suspended? question. I understood this answer that instead using ManagedScheduledExecutorService directly I should use javax.ejb.TimerService but I only pass ManagedScheduledExecutorService to external library so I can not use javax.ejb.TimerService or javax.ejb.Schedule annotation in this external library. I solved my issue by using javax.ejb.TimerService to initialize external library. I did sth like this:

@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
    }
}

This solution has some drawbacks. If application is deployed on launched Wildfly then library is initialized during deploying. Unfortunately if Wildfly is starting after wildfly restart then initialization is executed after deployment (after Wildfly finish launching). It means that after restarting Wildfly I still have to wait for my external library initialization. It can have impact on integration test. Arquillian deploys on launched Wildfly so checking if scheduled executor service is available allows to avoid sleep or sth like that in Arquillian integration tests.

I tried following solution but it does not work. Deploying application never ends because while loop never ends.

@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

    }
Mariusz
  • 1,907
  • 3
  • 24
  • 39