I'm currently using the Quartz scheduler framework in a Java standalone application. The basic functionality of this application is to execute some jobs periodically.
So far everything works quite well but I think there would be some benefits if I would use the Java EE 6 platform. For example database handling, email notifications, providing a web interface etc. would be simplified that way.
Now I'd like to hear some opinions regarding the Java EE (6) timer service. Is this the right tool to manage the periodical execution of different jobs? Perhaps I should mention that all jobs are created and modified programmatically. The execution intervals are between some minutes, hours or even days. And there will be at most a few hundred jobs scheduled at one time (usually with varying intervals or execution dates).
The API of the timer service seems to be able to do what I want without using an additional framework like Quartz directly inside the application (even though Quartz may still be used under the hood depending on the application server).
I'm just not sure if plain Jave EE is the right tool for such requirements. Does anyone have practical experience with the timer services in Java EE 6? Do you see any problems regarding my requirements?
I haven't used the JEE timer service, but then, I never saw a need for Quartz, either - I've always found the java.util.Timer and TimerTask classes to be sufficient. It may depend on how much interaction with the jobs you require after they've been created, though.
Ping & DNS - updated with new look and Ping home screen widget
thanks for your advice. Quartz offers some nice features which come in quite handy in this case, so I guess it would make things more difficult to rely on a plain Timer.
As you already mentioned one thing is interaction with jobs. For example Quartz makes it easy with automatic listener notifications to intercept a job before, during or after its execution and it's even trivial to veto for a job execution depending on some conditions.
Additionally there are a lot of things which make management of jobs a breeze. You can temporarily suspend, delete or update jobs easily. You can make jobs persistent by using a JDBC backend etc.
As I'm already using some of the features of Quartz it would be one step back to use an ordinary Timer, although I agree that it would surely be enough to schedule simple jobs. Surely it would be possible to implement a lot of these features myself based on the Timer API but I think that would be a questionable solution.
On the other hand the features of the Java EE timer service together with other components of the new JEE 6 platform sound very promising. As I'm using JPA 2 for the persistence layer of the application it would be nice to benefit from transaction support and easier entity management of the container. Additionally messaging is involved in this application which would be easier to achieve with JMS or similar. Exposing some functionality via web services would be nice too (currently I'm using RMI for communication with another application). And finally it would be nice to create a web frontend for the application which is now realized in another application which uses the same database backend but has limited features.
I hope this explains why I would like to switch to Java EE, in particular the new release JEE 6.
On the one hand, the EJB Timer service won't gain you much more than simply having the Quartz callback methods calling a Session Bean method to do the work you need, since effectively that's all that the Timer service is doing.
In both cases there can be security/role issues (since the Timer service doesn't "log in" as anybody, you don't know "who" is making the EJB calls, well you do, it's Anonymous, but that's not helpful if Frank scheduled the job), if that's an issue for you.
JEE 6 timers are much better than JEE 5 timers, but most of that capability is available only from code (vs, say, the servers admin console, though some server may offer this facility, I don't know any that do. Services like "how many jobs are pending in the timer service" from the console.)
For example, in JEE 6 you can annotate a bean to "run every 5 minutes" or "every friday" etc.
That's all well and good, but if you wish to change that schedule, you get to rebuild/redeploy your application.
The other aspect to consider is that, by default, JEE timers are persistent. In JEE 6, this is now optional, it's default, but you can change it, however it was not optional in JEE 5.
By persistent that means that if you create a Timer that runs every 5 minutes, and restart the server, then when the server restarts the Timer will remain and execute again. Very likely it will execute immediately if the 5 minute window has passed, as Timers execute when the current time has passed their scheduled start time.
This is all well and good.
Where it become frustrating is two fold.
First, if you create a Timer for some future date (say, "run this next Wednesday"), then that Timer will fire next Wednesday, even if the server restarts.
However, the Timer is persistent to the APPLICATION, not the SERVER. If the server restarts you're good. If you redeploy the application, the timer Goes Away. Since the application is removed form the server (for redeployment), all of its Timers go with it.
That means your Wednesday job needs to be rescheduled.
If you were naive, every time the application started, you would create a Timer job that "runs on Wednesday". But if you simply rebooted the server, you'd end up with TWO jobs that run on Wed. So, you need to scan the current timer list to see if your job is already queued up. If "hard coding" the schedule in your bean is sufficient, that handles this problem nicely.
The other issue is that the container will start all (ALL) expired Timers as soon as the container has restarted. The problem here first is the potential "Timer storm". Say you have 5 jobs that are schedule to run in 1, 2, 3, 4 and 5 minutes. You have some issue with the system and it's down for 10 minutes before its restarted. When it's restarted, all 5 jobs will begin automatically, and simultaneously. Your container may have some way to throttle how may Timers can run at the same time.
But the other issue is that the lifecycle of Timers were, in JEE 5, undefined. In JEE 5, there was really no place to "hook in" when the application started up. Many folks hook in to a ServletContextListener to let them know when an application is starting up. This mostly works, but the nut is that the EJB tier pretty much has to be already running before the Servlet tier fires up (since the Servlet tier will very likely be calling the EJB tier). So, by the time the ServletContextListener.contextInitialized method was called, any expired Timer sessions may well be off and away and running.
This is important in case your application start up need to initialize anything the Timer job may need to run, like some caches or other services.
JEE 6 MAY address this, indirectly, with the Singleton Session Bean. You can add @Startup to a Singleton Session Bean and it's guaranteed to be called before any EXTERNAL client requests are made. External as in external to the application. Are Timers external calls? *shrug* I dunno.
So, these are some "gotchas" regarding EJB timers that you should be aware of.
If it were me, I'd manage all of the timers in my application, and mark them as non-persistent in EJB. That simplifies a lot of issues. Also, since methods can be Asynchronous, that relieves some of the processing issues with Timers (as they were the only "approved" way to run background processes in the EJB tier in JEE 5 since you shouldn't spawn threads).
We manage all of our timers in our app. On startup we lock down our Timer jobs, and then purge the EJB Timer service and reapply the timers from our DB. Our Timer jobs can't run until we've triggered that the system has started up to OUR satisfaction, and they just block waiting for that, and then quietly exit hoping they're rescheduled.
But we're on JEE 5, so we have to do that. JEE 6 would simplify my code a little, but likely not that much.
thanks a lot for these VERY detailed insights into your experiences with scheduling mechanisms in Java. Obviously you have used them more than once before :-)
I've already worked on a solution based on Quartz inside a standalone daemon application and I've also experimented with Quartz inside a web application in Tomcat. Therefore I've already experienced some of the problems you mentioned myself - for example persistent jobs or the "timer storm" like you named it.
The idea to use timers in JEE 6 was just to experiment a little bit with this improved API and compare it to the other solutions I've already tried. So it's not mission critical for me to use timers in JEE successfully. Thankfully your detailed explanations of the problems to be aware of will help me to get things working (or at least test what I want to test) quickly I guess.
Anyway thank you very much for taking so much time and sharing your thoughts and experiences!