3

I'm scheduling background task to run in fixed-intervals, but as tomcat is running in multiple instances (i.e. multiple start Apache servers; 3 in my case), then the task runs 3 times in each interval.. I would like it to run once (no matter the number of Tomcat instances running).

I'm running a servlet loaded on startup (in web.xml) which will initiate my task:

<servlet>
    <servlet-name>OnInit</servlet-name>
    <servlet-class>box.OnInit</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet> 

OnInit class initiate single instance of that class:

public class BGTaskRefresh {
    private static BGTaskRefresh refreshTaskFactory = null;
    private final Timer timer = new Timer();

    public BGTaskRefresh() {}
    public static void init()
    {
        if( refreshTaskFactory == null )
        {
            refreshTaskFactory = new BGTaskRefresh();
            refreshTaskFactory.start();
        }
    }

    public void start() 
    {
        timer.schedule(
            new TimerTask() 
            {
                    public void run() 
                    {
                        boxService box = new boxService();
                        box.refreshMethod();
                    } 
                },                      
                5 * 60 * 1000,   // 5-Min Delay for first run
            60 * 60 * 1000); // 60-Mins (Interval between 2 runs)                   
    }
}
Alex K
  • 22,315
  • 19
  • 108
  • 236
Haim
  • 63
  • 5

2 Answers2

3

You might want to have a look at , especially its clustering capabilities:

two muppets
(source: quartz-scheduler.org)

This might be an overkill in your situation, but Quartz will take care of running the job on only a single instance (using database for synchronization) and will automatically run the job on an idle server.

Another option is and distributed locks and queues it provides.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • It seems i (we?) are missing something here. Isn't Java Timer built-in capabilities should be able to handle it? I mean, having fixed-intervals is quite common, and also having your application server run in multiple instances.. – Haim Mar 05 '12 at 12:56
  • @Haim: how? [`Timer`](http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html) is just a Java class managing few threads. If you have several JVMs (possibly on different machines), how is that class suppose to know about other instances? They are completely independent - that's why your task is executed on each of them and that's why you have answers mentioning Quartz, database and file locking - because you need some sort of synchronization/coordination outside of the JVM. Or am I missing something? – Tomasz Nurkiewicz Mar 05 '12 at 12:59
0

You will need some sort of synchronization mechanism. Although ideally you'd want a distributed scheduler (e.g. Quartz cluster), considering your usage scenario you're likely to have either some mechanism for shared session state or a shared database underlying your application; you can simply record the operation and grab a database-based lock to ensure only one instance will run the command at a time (and double-check after the lock grab to ensure you're not running the same task twice).

Here's one article I've found with a technique for DB-based locking: http://blog.udby.com/archives/15

Tomer Gabel
  • 4,104
  • 1
  • 33
  • 37