3 Replies Latest reply on Jun 16, 2016 1:54 AM by Christian Kölle

    Problem starting batch job with ManagedScheduledExecutorService

    Christian Kölle Newbie

      Hi

       

      I have a problem with running batch jobs in Wildfly 9 when starting them with the help of the ManagedScheduledExecutorService. Here's what i try:

       

      1. I have a MBean for activating the scheduling via JMX:

       

      @Singleton

      @Startup

      public class MyJobController implements MyJobMXBean {

        /**

        * The executor service

        */

        @Resource

        ManagedScheduledExecutorService executor;

       

        @Override

        public void executeTaskNow() {

        new MyJobRunner().run();

        }

       

        @Override

        public void resumeTask() {

        executor.schedule(new MyJobRunner(), new Trigger() {

       

        public Date getNextRunTime(LastExecution lastExecutionInfo, Date taskScheduledTime) {

        Calendar cal = Calendar.getInstance();

        cal.add(Calendar.SECOND, 10);

        logger.info("Schedule time: " + cal.getTime().toString());

        return cal.getTime();

        }

       

        public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime) {

        return false;

        }

       

        });

        }

      }

       

       

      MyJobRunner:

       

      public class MyJobRunner implements Runnable {

       

        @Override

        public void run() {

        JobOperator jo = BatchRuntime.getJobOperator();

        try {

        jo.start("MyJob", new Properties());

        } catch (Throwable e) {

        e.printStackTrace();

        }

        }

      }

       

      The structure of the deployment is:

       

      MyEar.ear

          META-INF

              beans.xml

          MyEJBJar.jar

         

      with:

       

      MyEJBJar.jar

          META-INF

              batch-jobs

                  MyJob.xml

              beans.xml

             

      When i start the Job via the executeTaskNow method everythings works fine. But when i try to schedule the job via the resumeTask method i get an exception:

       

      09.06.2016 07:55:47.041; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) javax.batch.operations.JobStartException: JBERET000601: Failed to get job xml file for job EA13.xml

      09.06.2016 07:55:47.041; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.jberet.creation.ArchiveXmlLoader.getJobXml(ArchiveXmlLoader.java:129)

      09.06.2016 07:55:47.042; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.jberet.creation.ArchiveXmlLoader.loadJobXml(ArchiveXmlLoader.java:91)

      09.06.2016 07:55:47.042; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.jberet.operations.JobOperatorImpl.start(JobOperatorImpl.java:103)

      09.06.2016 07:55:47.042; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at ...MyJobRunner.run(JobRunner.java:29)

      09.06.2016 07:55:47.042; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

      09.06.2016 07:55:47.043; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at java.util.concurrent.FutureTask.run(FutureTask.java:266)

      09.06.2016 07:55:47.043; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.glassfish.enterprise.concurrent.internal.ManagedFutureTask.run(ManagedFutureTask.java:141)

      09.06.2016 07:55:47.043; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.access$101(ManagedScheduledThreadPoolExecutor.java:383)

      09.06.2016 07:55:47.043; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedScheduledFutureTask.run(ManagedScheduledThreadPoolExecutor.java:532)

      09.06.2016 07:55:47.043; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.glassfish.enterprise.concurrent.internal.ManagedScheduledThreadPoolExecutor$ManagedTriggerSingleFutureTask.run(ManagedScheduledThreadPoolExecutor.java:587)

      09.06.2016 07:55:47.044; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

      09.06.2016 07:55:47.044; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

      09.06.2016 07:55:47.044; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at java.lang.Thread.run(Thread.java:745)

      09.06.2016 07:55:47.044; ERROR [stderr] (EE-ManagedScheduledExecutorService-default-Thread-1) at org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:250)

       

      I already tried to add the batch XML file to the META-INF of the ear and also tried the workaround describes here (http://rogersuen.blogspot.ch/2015/11/wildfly9-execute-batch-jobs-from-jar-in-war.html). I saw the also this bug report (https://issues.jboss.org/browse/WFLY-4988) but i don't think this applies here.

       

      Any ideas?

       

      Best regards

      Christian

        • 1. Re: Problem starting batch job with ManagedScheduledExecutorService
          James Perkins Master

          This seemed to work for me in a test. The only difference was I wasn't using an MBean. I just used a startup EJB with a @PostConstruct annotation on the method to start the batch jobs.

          package org.jboss.example.batch.ejb.startup;
          
          import java.util.Calendar;
          import java.util.Date;
          import java.util.Properties;
          import javax.annotation.PostConstruct;
          import javax.annotation.Resource;
          import javax.batch.operations.JobOperator;
          import javax.batch.runtime.BatchRuntime;
          import javax.ejb.Singleton;
          import javax.ejb.Startup;
          import javax.enterprise.concurrent.LastExecution;
          import javax.enterprise.concurrent.ManagedScheduledExecutorService;
          import javax.enterprise.concurrent.Trigger;
          
          import org.jboss.logging.Logger;
          
          @Singleton
          @Startup
          public class StartBatchJobs {
              private static final Logger logger = Logger.getLogger(StartBatchJobs.class);
          
              @Resource
              private ManagedScheduledExecutorService executor;
          
              private final String[] autoStartJobs = {
                      "simple"
              };
          
              @PostConstruct
              public void startJobs() {
                  for (String jobXml : autoStartJobs) {
                      executor.schedule(new JobRunner(jobXml, new Properties()), new Trigger() {
          
                          public Date getNextRunTime(final LastExecution lastExecutionInfo, final Date taskScheduledTime) {
                              final Calendar cal = Calendar.getInstance();
                              cal.add(Calendar.SECOND, 10);
                              logger.infof("Schedule time: %s", cal.getTime());
                              return cal.getTime();
                          }
          
                          public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime) {
                              return false;
                          }
          
                      });
                  }
              }
          
          
              private static class JobRunner implements Runnable {
                  private final String jobName;
                  private final Properties properties;
          
                  private JobRunner(final String jobName, final Properties properties) {
                      this.jobName = jobName;
                      this.properties = properties;
                  }
          
          
                  @Override
                  public void run() {
                      final JobOperator jobOperator = BatchRuntime.getJobOperator();
                      try {
                          jobOperator.start(jobName, properties);
                      } catch (Exception e) {
                          logger.errorf(e, "Failed to start batch job %s", jobName);
                      }
                  }
              }
          }
          
          

           

          --

          James R. Perkins

          • 2. Re: Problem starting batch job with ManagedScheduledExecutorService
            jaikiran pai Master

            It looks like the Thread context classloader isn't set to the application's classloader when that ManagedScheduledExecutorService triggers your job. I don't know what the spec says about it, but as a workaround, you can try this in your code:

            public class MyJobRunner implements Runnable {
              @Override
              public void run() {
            
                  final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
                  // set the TCCL to our application's classloader
                  Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
                  try {
                    JobOperator jo = BatchRuntime.getJobOperator();
                    jo.start("MyJob", new Properties());
                } catch (Throwable e) {
                    throw new RuntimeException("Failed to start job", e);
                } finally {
                    // reset the TCCL back to the previous classloader
                    Thread.currentThread().setContextClassLoader(oldClassLoader);
            
                }
              }
            
            }
            
            
            • 3. Re: Problem starting batch job with ManagedScheduledExecutorService
              Christian Kölle Newbie

              Thanks for the answers. The workaround from Jaikiran works perfectly.

               

              In the meantime i found another working solution without fiddling with the class loaders ;-)

               

              @Resource

              TimerService timerService;

               

              @Override

              public void resumeTask() {

                   ScheduleExpression expression = new ScheduleExpression();

                   expression.second("0").minute("*/5").hour("*");

                   timerService.createCalendarTimer(expression);

              }

               

              @Timeout

              private void run() {

                   new JobRunner.run();

              }