This question already has answers here:
How to run a background task in a servlet based web application?
(5 answers)
Closed 7 years ago.
I am using JSP/Servlet on Apache Tomcat. I have to run a method every 10 minutes. How can I achieve this?
As you're on Tomcat, which is just a barebones servletcontainer, you can't use EJB's #Schedule for this which is recommended by Java EE specification. Your best bet is then the ScheduledExecutorService from Java 1.5's java.util.concurrent package. You can trigger this with help of a ServletContextListener like follows:
#WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeTask(), 0, 10, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
where the SomeTask class look like this:
public class SomeTask implements Runnable {
#Override
public void run() {
// Do your job here.
}
}
If you were actually using a real Java EE container with EJB support and all on em (like Glassfish, JBoss AS, TomEE, etc), then you could use a #Singleton EJB with a #Schedule method. This way the container will worry itself about pooling and destroying threads. All you need is then the following EJB:
#Singleton
public class SomeTask {
#Schedule(hour="*", minute="*/10", second="0", persistent=false)
public void run() {
// Do your job here.
}
}
Note that this way you can continue transparently using container managed transactions the usual way (#PersistenceContext and so on), which isn't possible with ScheduledExecutorService — you'd have to manually obtain the entity manager and manually start/commit/end transaction, but you would by default already not have another option on a barebones servletcontainer like Tomcat anyway.
Note that you should never use a Timer in a supposedly "lifetime long" running Java EE web application. It has the following major problems which makes it unsuitable for use in Java EE (quoted from Java Concurrency in Practice):
Timer is sensitive to changes in the system clock, ScheduledExecutorService isn't.
Timer has only one execution thread, so long-running task can delay other tasks. ScheduledExecutorService can be configured with any number of threads.
Any runtime exceptions thrown in a TimerTask kill that one thread, thus making Timer dead, i.e. scheduled tasks will not run anymore (until you restart the server). ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want. Task which threw exception will be canceled, but other tasks will continue to run.
Read on ScheduledExecutorService it has to be initiated by a ServletContextListener
public class MyContext implements ServletContextListener
{
private ScheduledExecutorService sched;
#Override
public void contextInitialized(ServletContextEvent event)
{
sched = Executors.newSingleThreadScheduledExecutor();
sched.scheduleAtFixedRate(new MyTask(), 0, 10, TimeUnit.MINUTES);
}
#Override
public void contextDestroyed(ServletContextEvent event)
{
sched.shutdownNow();
}
}
Also, you may try using the Java Timer from a ServletContextListener but it's not recommended in a Java EE container since it takes away control of the Thread resources from the container. (the first option with ScheduledExecutorService is the way to go).
Timer timer = new Timer("MyTimer");
MyTask t = new MyTask();
//Second Parameter is the specified the Starting Time for your timer in
//MilliSeconds or Date
//Third Parameter is the specified the Period between consecutive
//calling for the method.
timer.schedule(t, 0, 1000*60*10);
And MyTask that implements TimerTask is a class that implements the Runnable interface so you have to override the run method with your code:
class MyTask extends TimerTask
{
public void run()
{
// your code here
}
}
Related
Currently I am building a spring standalone program in order to learn new methods and architectures.
The last few days I tried to learn scheduler. I never used them before so I read some articles handling the different possible methods. Two of them are especially interesting: The spring nativ #Scheduler and Quartz.
From what I read, Spring is a little bit smaller then Quartz and much more basic. And quartz is not easy to use with spring (because of the autowired and components).
My problem now is, that there is one thing I do not understand:
From my understanding, both methods are creating parallel Threads in order to asynchronously run the jobs. But what if I now have a spring #Service in my main Application, that is holding a HashMap with some information. The data is updated and changed with user interaction. Parallel there are the scheduler. And a scheduler now whants to use this HashMap from the main application as well. Is this even possible?
Or do I understand something wrong? Because there is also the #Async annotation and I did not understand the difference. Because a scheduler itself is already parallel to the main corpus, isn't it?
(summing up, two questions:
can a job that is executed every five seconds, implemented with a scheduler, use a HashMap out of a service inside the main program? (in spring #Scheduler and/or in Quartz?)
Why is there a #Async annotation. Isn't a scheduler already parallel to the main process?
)
I have to make a few assumptions about which version of Spring you're using but as you're in the process of learning, I would assume that you're using spring-boot or a fairly new version, so please excuse if the annotations don't match your version of Spring. This said, to answer your two questions the best I can:
can a job that is executed every five seconds, implemented with a scheduler, use a HashMap out of a service inside the main program? (in spring #Scheduler and/or in Quartz?)
Yes, absolutely! The easiest way is to make sure that the hashmap in question is declared as static. To access the hashmap from the scheduled job, simply either autowire your service class or create a static get function for the hashmap.
Here is an example of a recent Vaadin project where I needed a scheduled message sent to a set of subscribers.
SchedulerConfig.class
#Configuration
#EnableAsync
#EnableScheduling
public class SchedulerConfig {
#Scheduled(fixedDelay=5000)
public void refreshVaadinUIs() {
Broadcaster.broadcast(
new BroadcastMessage(
BroadcastMessageType.AUTO_REFRESH_LIST
)
);
}
}
Broadcaster.class
public class Broadcaster implements Serializable {
private static final long serialVersionUID = 3540459607283346649L;
private static ExecutorService executorService = Executors.newSingleThreadExecutor();
private static LinkedList<BroadcastListener> listeners = new LinkedList<BroadcastListener>();
public interface BroadcastListener {
void receiveBroadcast(BroadcastMessage message);
}
public static synchronized void register(BroadcastListener listener) {
listeners.add(listener);
}
public static synchronized void unregister(BroadcastListener listener) {
listeners.remove(listener);
}
public static synchronized void broadcast(final BroadcastMessage message) {
for (final BroadcastListener listener: listeners)
executorService.execute(new Runnable() {
#Override
public void run() {
listener.receiveBroadcast(message);
}
});
}
}
Why is there a #Async annotation. Isn't a scheduler already parallel to the main process?
Yes, the scheduler is running in its own thread but what occurs to the scheduler on long running tasks (ie: doing a SOAP call to a remote server that takes a very long time to complete)?
The #Async annotation isn't required for scheduling but if you have a long running function being invoked by the scheduler, it becomes quite important.
This annotation is used to take a specific task and request to Spring's TaskExecutor to execute it on its own thread instead of the current thread. The #Async annotation causes the function to immediately return but execution will be later made by the TaskExecutor.
This said, without the #EnableAsync or #Async annotation, the functions you call will hold up the TaskScheduler as they will be executed on the same thread. On a long running operation, this would cause the scheduler to be held up and unable to execute any other scheduled functions until it returns.
I would suggest a read of Spring's Documentation about Task Execution and Scheduling It provides a great explanation of the TaskScheduler and TaskExecutor in Spring
I'm starting to learn Java with Spring and I've written some simple scheduled tasks.
I don't understand the mechanism that the framework uses so the application does not exit after the getBean call. How come the application keeps on printing "Hi"?
public class Application {
public static void main(String[] args) {
...
PeriodicTask task = appCtx.getBean(PeriodicTask.class);
}
}
public class PeriodicTask {
#Scheduled(fixedRate = 5000)
public void periodic() {
System.out.println("Hi");
}
}
Given #Scheduled, I'm going to assume your ApplicationContext has some scheduled configuration. This means that your are creating (implicitly or explicitly) a SchedulerExecutorService which spawns non-daemon threads. The application will not end until all non-daemon threads have completed. One of these threads is executing your periodic method every 5000 milliseconds.
Now, you could put your ApplicationContext instantiation in a try-with-resources. Once execution leaves the try block, the ApplicationContext would be closed, shutting down the ScheduledExecutorService and eventually terminating your program.
I'm trying to start a thread in a Singleton EJB but java.lang.IllegalStateException is being thrown. This is my (cut-down) class:
Singleton
#LocalBean
#Startup
public class WatcherEJB {
#Resource(name = "concurrent/masterActionsThreadFactor")
ManagedThreadFactory threadFactory;
Thread watcherThread;
#PostConstruct
public void startUp() {
//Setup the listener using the ThreadFactory
watcherThread = threadFactory.newThread(new Runnable() {
#Override
public void run() {
//System.out.println("Watcher Thread started");
}
});
watcherThread.start(); //java.lang.IllegalStateException thrown here
}
}
I'm assuming that there's a problem with when I'm trying to start the Thread object or does Java EE 7 not allow Managed threads in singletons?
What application server do You use?
If it's WildFly You probably run into this issue: https://issues.jboss.org/browse/WFLY-2343
I came across this thread when looking for a solution and I thought that I would post this link to a thread which I believe answers the question. I know it has been a while since this question was asked but it should be useful for future reference!
Glassfish 4 - Using Concurrency API to create Managed Threads
I'm doing my graduation project, and have run into a dilemma here.
I need to make an application that generates PDFs and emails them to people on a schedule defined by data in the database.
I'm working for a company with this project, and we already have a GlassFish application server that we use. It would be best if the entire solution is delivered in one package, as it is now.
Client with webstart
Web Application etc. is all in one package
My new service needs to run on a separate thread, generate reports and send them out on emails. From what I can read on the web, running your own threads in an application server as GlassFish is highly discouraged, so it sounds like I need to make my own separate application.
Can this really be? What are your comments, and what are the best practices for this?
#Schedule
If you are using Ejb 3.1 (glassfish 3.x), you may use the #Schedule annotation to have the container invoke a method in a specified interval or at a given calendar time. Allowing you to avoid handling threads in your own code
Read about ejb 3.1 timer
#Stateless
public class LabbBean {
#EJB
WorkerEjb workerEjb;
#Schedule(second="*/5", minute="*",hour="*", persistent=false)
public void myMethod() {
for (all jobs found in db){
workerEjb.workerMethod(job);
}
}
}
#Stateless
public class WorkerEjb {
#Asynchronous
public void workerMethod(job) {
//Send emails
}
}
If you wanted to do the work in separate threads, the #Schedule annotated method could call a worker-ejb with the worker-method annotated as #Asynchronous
#Timeout
I just realised you wanted the schedule to be initiated from the database. An option the would be to initiate a bunch of timers programmatically using a #Singleton ejb with #Startup annotation. The timeout annotated method would be called in separate threads if some timers run out at the same time.
#Singleton
#Startup
public class LabbBean {
#Resource
protected TimerService timerService;
#PostConstruct
public void init() {
//Init your timers from the data in the database here
for (all your timers) {
TimerConfig config = new TimerConfig();
config.setInfo("timer1");
config.setPersistent(false);
ScheduleExpression schedule = new ScheduleExpression();
schedule.dayOfMonth(10);
schedule.minute(2);
timerService.createCalendarTimer(schedule, config);
}
}
//method called when timeout occurs
#Timeout
public void timeoutHandler(Timer timer) {
String name = timer.getInfo().toString();
System.out.println("Timer name=" + name);
}
}
I need to create an interval Timer that is set to run once a week automatically. I don't want it to start based on user input, but I want it to be created when the application is deployed to the server. Every example that I have seen has another class starting the timer. I don't want to use a message driven bean to create the timer because the audit should just query a database for a given time period and is not based off of actions which send messages.
I have included an example of a Timer. In the example below, the timer should fire every 10 minutes. As a test I want the timer to fire every 10 minutes so I can test the timer.
#Stateless
public class TimerTest implements
TimerTestLocal, TimerTestRemote{
#Resource
private TimerService timerService;
private Logger log = Logger.getLogger(TimerTest.class);
private long interval = 1000 * 60 * 10;
private static String TIMER_NAME = "AuditTimer";
public void scheduleTimer() throws NamingException {
// TODO Auto-generated method stub
Calendar cal = Calendar.getInstance();
//cal.set(Calendar.HOUR_OF_DAY, 23);//run at 11pm
//cal.set(Calendar.MINUTE, 00);
//cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm");
log.debug("schedule for: " + sdf.format(cal.getTime()));
timerService.createTimer(cal.getTime(), interval, TIMER_NAME);
}
public void cancelTimer() {
for(Object obj : timerService.getTimers())
{
Timer timer = (Timer)obj;
if(timer.getInfo().equals(TIMER_NAME))
timer.cancel();
}
}
#Timeout
public void timerEvent(Timer timer) {
log.debug("timer fired");
}
}
So is there any way that I can start this timer when the application is deployed? I don't think it's a good idea to put the creation of the Timer in a #PostConstruct method because of class loaders on in the server.
If your project can use jee6 / ejb3.1 there is a much better solution to this problem.
http://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html
#javax.ejb.Schedule(minute="*/10", hour="*")
public void automaticTimeout() {
logger.info("Automatic timeout occured");
}
By using the new #Schedule annotation you have extensive control about when and how often a timeout method will be called. The big upside: you no longer have to start the timer "from outside".
Oracle writes:
Automatic timers are created by the EJB container when an enterprise
bean that contains methods annotated with the #Schedule or #Schedules
annotations is deployed. An enterprise bean can have multiple
automatic timeout methods, unlike a programmatic timer, which allows
only one method annotated with the #Timeout annotation in the
enterprise bean class.
The way that I've done timers in the past is to create a context listener in the web.xml to configure the timer.
That way you can ensure that it is started with the container, and shut down cleanly when the app is taken down.
I don't know whether using the contextListener to start the timer can work. From this article, how to use EJb 3 timer in a weblogic 10 cluster, it looks like you may run into some problems in weblogic 10.3.2.