11

I want a process to run after I start my webservice, and then every 30 minutes or so afterwards, (I'm testing it with a smaller delay for now, just to see if it works), but my process never runs more than once. What am I doing wrong?

Here is my code:

@WebListener
public class SchedulerService implements ServletContextListener{

    @Autowired
    UpdateSubscriberService updateSubscriberService;

    ScheduledExecutorService scheduledExecService;

    public SchedulerService(){
        scheduledExecService = Executors.newSingleThreadScheduledExecutor();
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        scheduledExecService.shutdown();
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        scheduledExecService.scheduleWithFixedDelay(new Runnable(){
            @Override
            public void run() {
                Date date = new Date(System.currentTimeMillis());
                System.out.println("Running scheduled update check " + date.toString());
                updateSubscriberService.checkForUpdates();
            }
        }, 60, 30, TimeUnit.SECONDS);
    }
}
MMAdams
  • 1,508
  • 15
  • 29

2 Answers2

25

See this longer Answer of mine on a similar Question.

Wrap run code with try catch

Just a guess: An exception is being thrown. A ScheduledExecutorService halts silently if it encounters an Exception, with no further scheduled work performed.

The run method’s code should always be surrounded by a try-catch to handle and absorb any thrown Exception.

By the way, the terribly flawed Date class has been supplanted by the modern java.time classes. Specifically replaced by Instant.

 @Override
 public void run() {
    try {  // Let no Exception reach the ScheduledExecutorService.
        Instant instant = Instant.now() ;
        System.out.println("Running scheduled update check " + instant );
        updateSubscriberService.checkForUpdates();
    } catch ( Exception e ) {
        System.out.println( "ERROR - unexpected exception" );
    }
}

Stub out run method

Take baby steps. Begin with a run method that does nothing but a System.out.println.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • When I changed it to just a print statement, it executed multiple times, as it should, so at least I know now that the problem isn't in the scheduling code! – MMAdams May 17 '17 at 18:33
  • Hello Basil, What if I want to use the ScheduledExecutorService to run just once? Why I'm asking this coz I have 2 classes out of which one class has to be scheduled and the other class can run just once. – Suresh Apr 12 '18 at 04:32
  • @mannedear Then use another executor service other than `ScheduledExecutorService`. Study the [Tutorial](https://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html) and search Stack Overflow to learn more. – Basil Bourque Apr 12 '18 at 15:25
  • @BasilBourque I'm planning to use a flag and call the `ScheduledExecutorService` class cancel method. What's your call on this? – Suresh Apr 12 '18 at 16:22
  • @mannedear You need to post your own Question, and spell out the situation. – Basil Bourque Apr 12 '18 at 17:42
  • Very strange, my code is not throwing an exception, yet still I needed to do this! – Dan Rayson Oct 24 '18 at 13:31
  • @DanRayson In your try-catch, did you dump the caught exception to console with `System.out.println`? I’ll bet you are indeed throwing and now catching an exception. – Basil Bourque Oct 24 '18 at 15:32
  • @BasilBourque Yep, I put a breakpoint in the catch to see if it did indeed throw an exception, and my specific code did not. High strangeness, so I'm not pretending to understand it lol. – Dan Rayson Oct 24 '18 at 15:48
  • 1
    "Take baby steps",this is a very good advice, lead me to sloved my problem,thanks very much – jack jin Dec 25 '20 at 16:09
1

Just in case you are ever in a position where the code MUST run once every-so-many-seconds even if the last run hasn't completed yet (which can be very dangerous if not managed properly), you can launch your process inside a different thread inside the timer. Here is sample code.

ScheduledExecutorService scheduledExecService = newSingleThreadScheduledExecutor();
scheduledExecService.scheduleWithFixedDelay(new Runnable()
{
    @Override
    public void run()
    {
        // This should be in a try-catch because any error here
        // will stop the recurrence
        try
        {
            // The timer will only repeat if the last run is finished. So
            // we put each new process in a different thread than the timer
            // itself, so the last timer call "finishes" as soon as the process
            // leaves the timer's thread.
            Thread t = new Thread(new Runnable()
            {
                public void run()
                {
                    try
                    {
                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        MyProcessThatShouldRunEverySoManySecondsNoMatterWhat();
                    }
                    catch (Exception erTimerThread)
                    {
                        Log.e("Error", erTimerThread.toString());
                    }
                }
            });
            t.setPriority(2);
            t.start();
        }
        catch (Exception erTimer)
        {
            Log.e("Error", erTimer.toString());
        }
    }
}, 0, 60, java.util.concurrent.TimeUnit.SECONDS);
gcdev
  • 1,406
  • 3
  • 17
  • 30