I'm using Java and I want to keep a servlet continuously running in my application, but I'm not getting how to do it. My servlet has a method which gives counts of the user from a database on a daily basis as well as the total count of the users from the whole database. So I want to keep the servlet continuously running for that.
Your problem is that you misunderstand the purpose of the servlet. It's intented to act on HTTP requests, nothing more. You want just a background task which runs once on daily basis.
EJB available? Use #Schedule
If your environment happen to support EJB (i.e. a real Java EE server such as WildFly, JBoss, TomEE, Payara, GlassFish, etc), then use #Schedule instead. Here are some examples:
#Singleton
public class BackgroundJobManager {
#Schedule(hour="0", minute="0", second="0", persistent=false)
public void someDailyJob() {
// Do your job here which should run every start of day.
}
#Schedule(hour="*/1", minute="0", second="0", persistent=false)
public void someHourlyJob() {
// Do your job here which should run every hour of day.
}
#Schedule(hour="*", minute="*/15", second="0", persistent=false)
public void someQuarterlyJob() {
// Do your job here which should run every 15 minute of hour.
}
#Schedule(hour="*", minute="*", second="*/5", persistent=false)
public void someFiveSecondelyJob() {
// Do your job here which should run every 5 seconds.
}
}
Yes, that's really all. The container will automatically pickup and manage it.
EJB unavailable? Use ScheduledExecutorService
If your environment doesn't support EJB (i.e. you're not using not a real Java EE server, but a barebones servletcontainer such as Tomcat, Jetty, etc), then use ScheduledExecutorService. This can be initiated by a ServletContextListener. Here's a kickoff example:
#WebListener
public class BackgroundJobManager implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
Where the job classes look like this:
public class SomeDailyJob implements Runnable {
#Override
public void run() {
// Do your daily job here.
}
}
public class SomeHourlyJob implements Runnable {
#Override
public void run() {
// Do your hourly job here.
}
}
public class SomeQuarterlyJob implements Runnable {
#Override
public void run() {
// Do your quarterly job here.
}
}
public class SomeFiveSecondelyJob implements Runnable {
#Override
public void run() {
// Do your quarterly job here.
}
}
Do not ever think about using java.util.Timer/java.lang.Thread in a Java EE / Servlet based environment
Last but not least, never directly use java.util.Timer and/or java.lang.Thread in Java EE. This is recipe for trouble. An elaborate explanation can be found in this JSF-related answer on the same question: Spawning threads in a JSF managed bean for scheduled tasks using a timer.
I would suggest using a library like quartz in order to run the task at regular intervals. What does the servlet really do ? It sends you a report ?
You can use cron4j. http://www.sauronsoftware.it/projects/cron4j/manual.php
Implement two classes and call startTask() in main.
public void startTask()
{
// Create a Runnable
Runnable task = new Runnable() {
public void run() {
while (true) {
runTask();
}
}
};
// Run the task in a background thread
Thread backgroundThread = new Thread(task);
// Terminate the running thread if the application exits
backgroundThread.setDaemon(true);
// Start the thread
backgroundThread.start();
}
public void runTask()
{
try {
// do something...
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
In a production system that may have multiple non-jee containers running. Use anot enterprise scheduler like Quartz scheduler which can be configured to use a database for task maamgememt.
Related
In my Spring application, there is a scheduler for executing some task. Scheduled annotation is not used there because the schedule is quite complicated - it is dynamic and it used some data from the database. So simple endless cycle with thread sleeping is used. And sleeping interval is changed according to some rules. Maybe all this can be done with Scheduled annotation, but the question is not about that.
Below is simple example:
#Service
public class SomeService {
#PostConstruct
void init() {
new Thread(() -> {
while (true) {
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (Exception ex) {
System.out.println("end");
return;
}
}
}).start();
}
}
The code works fine but there is some trouble with killing that new thread. When I stop the application from Tomcat this new thread is continuing to run. So on Tomcat manage page I see that application is stopped, but in Tomcat log files I still see the output from the thread.
So what the problem? How I should change the code so the thread would be killed when the application is stopped?
Have you tried to implement a #PreDestroy method which will be invoked before WebApplicationContext is closed to change a boolean flag used in your loop? Though it seems strange that your objects are not discarded even when application is stopped...
class Scheduler {
private AtomicBoolean booleanFlag = new AtomicBoolean(true);
#PostConstruct
private void init() {
new Thread(() -> {
while (booleanFlag.get()) {
// do whatever you want
}
}).start();
}
#PreDestroy
private void destroy() {
booleanFlag.set(false);
}
}
Lets suppose there is spring boot web app with 2 classes mapped as #Controller and #Service. Service is injected into controller's field. I need my service to run task once a second to update some external data. Is there something wrong with this code?
#Component
public class MyService implements Runnable{
public MyService() {
new Thread(this).start();
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
// operations here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Though there are a lot of ways of creating a task, using job or spring task scheduler, below is one straightforward way.
Below task will run every second.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
System.out.println("hello");
}
}, 0, 1000); // o is delay time after which it starts, 1000 is time interval
Or you may want to refer here to implement spring task scheduler .
I want to create a hit counter register in my DB using Java Servlets. The main idea is use Filters and, in every user visit, increase the counter.
I don't want to make an update in the DB on every visit (I found this not too much efficient). I prefer to use an static variable that would be increased every visit and, at the end of the day, make an INSERT into the DB with the value of that variable and reset it to zero.
How could I do that? I don't know how to schedule an accion that say to my application every midnight make an INSERT and resets the variable...
Any idea?
Thank you! :)
You can use java.util.Timer
Timer t = new Timer("myTimer");
t.schedule(new TimerTask() {
#Override
public void run() {
if (count != lastCount) {
count = lastCount;
// TODO: update into database
}
}
}, 0, 2000);
After a long time searching for solutions, I found that Timer is not working well with Servlets, so I used this (and works great! :) This is the code for the filter:
public class LogVisitorsListener implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent sce) {
scheduler = Executors.newSingleThreadScheduledExecutor();
// It will be executed every 1 hour
scheduler.scheduleAtFixedRate(new DailyHitsRunnable(), 0, 1, TimeUnit.HOURS);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
scheduler.shutdownNow();
}
}
And my class DailyHitsRunnable:
public class DailyHitsRunnable implements Runnable {
#Override
public void run() {
try {
// stuff here...
}
catch(Throwable t) {
// catch work here...
}
}
}
It's very important to use that try/catch to avoid stopping the runnable action stops when something fails.
Regards!
I'm trying to use the new Concurrency API to inject a ManagedThreadFactory and use it per the Oracle tutorial.
Here is an example of what I'm talking about:
#Singleton
#Startup
public class Demo {
#Resource(name="concurrent/__DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;
#PostConstruct
public void startup() {
threadFactory.newThread(
new Runnable() {
#Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
I'm developing in Eclipse using the Glassfish plugin. When I republish after making a change, I always get this line in the server log. It appears once for every call to start() we make:
SEVERE: java.lang.IllegalStateException: Module (my application) is disabled
It's not actually throwing an IllegalStateException, just reporting that one has been thrown (and caught) inside Glassfish. The application deploys normally, but none of the threads start. If I subsequently republish and second time, the "error" goes away and the threads start as expected.
When I try to deploy the application to a "real" Glassfish setup (without Eclipse), it always reports successful deployment, and the logs do not contain the "error". But it still does not start the threads (even with repeated deployments).
Am I using the Concurrency API correctly? Could it be a configuration problem? For the record, I get the same behavior if I use a ManagedExcecutorService instead.
For the record, this question was asked a few months ago here: Can I start a ManagedThread in a Singleton Enterprise Java Bean?, but it was not really answered and I don't have the reputation yet to do anything but ask it again. Sorry!
UPDATE: This answer by Per-Axel Felth works. Thank you! I did some refactoring of that solution to attempt to isolate the workaround code from my original application logic:
#Singleton
#Startup
public class Demo {
#Resource(name="java:comp/DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;
#EJB private ConcurrencyInitializer concurrencyInitializer;
#EJB private Demo self;
#PostConstruct
public void startup() {
self.startThread();
}
#Asynchronous
public void startThread() {
//This line applies the workaround
concurrencyInitializer.init();
//Everything beyond this point is my original application logic
threadFactory.newThread(
new Runnable() {
#Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
/**
* A utility class used to get around a bug in Glassfish that allows
* Concurrency resources (ManagedThreadFactory, ManagedExecutorService, etc)
* to be injected before they are ready to be used.
*
* Derived from solution by Per-Axel Felth in: https://stackoverflow.com/questions/23900826/glassfish-4-using-concurrency-api-to-create-managed-threads
*/
#Singleton
public class ConcurrencyInitializer {
/**
* The number of milliseconds to wait before try to
*/
public static final long RETRY_DELAY = 500L;
/**
* The maximum number of concurrency attempts to make before failing
*/
public static final int MAX_RETRIES = 20;
/**
* Repeatedly attempts to submit a Runnable task to an injected ManagedExecutorService
* to trigger the readying of the Concurrency resources.
*
* #return true if successful (Concurrency resources are now ready for use),
* false if timed out instead
*/
public boolean init() {
final AtomicBoolean done = new AtomicBoolean(false);
int i = 0;
try {
while (!done.get() && i++ < MAX_RETRIES) {
executorService.submit(new Runnable() {
#Override
public void run() {
done.set(true);
}
});
Thread.sleep(RETRY_DELAY);
}
} catch(InterruptedException e) {
//Do nothing.
}
return done.get();
}
}
It's related to a Glassfish bug. I ran into the same bug myself some time ago and built a workaround. Thing is, the thread factory is injected alright, but if you use it "too early" you'll end up with an IllegalStateException.
My workaround code is listed below. It uses an injected executor service to detect when app is loaded and concurrency utils are available and then executes the actual startup logic in method init.
#Singleton
#Startup
public class Demo {
#Resource(name = "concurrent/__DefaultManagedThreadFactory")
ManagedThreadFactory threadFactory;
#Resource
ManagedExecutorService executorService;
#EJB
Demo me;
#PostConstruct
public void startup() {
me.waitAndInitialize();
}
#Asynchronous
public Future<?> waitAndInitialize() {
try {
final AtomicInteger done = new AtomicInteger(0);
int i = 0;
while (done.intValue() == 0 && i < 20) {
System.out.println("Is executor service up?");
i++;
executorService.submit(
new Runnable() {
#Override
public void run() {
int incrementAndGet = done.incrementAndGet();
System.out.println("Run by executorservice");
}
});
Thread.sleep(500);
}
if (done.intValue() == 0) {
Logger.getAnonymousLogger().severe("Waited a long time for the ExecutorService do become ready, but it never did. Will not initialize!");
} else {
init();
}
} catch (Exception e) {
Logger.getAnonymousLogger().log(Level.SEVERE, "Exception in waitAndInitialize: " + e.getMessage(), e);
}
return new AsyncResult<>(null);
}
private void init() {
threadFactory.newThread(
new Runnable() {
#Override
public void run() {
System.out.println("Do something.");
}
}
).start();
}
}
I suspect that your ManagedThreadFactory is not being injected correctly so the "Demo" component is not started.
The Java EE 7 spec mandates that a managed thread factory be made available in JNDI with the name "java:comp/DefaultManagedThreadFactory", therefore try changing #Resource to
#Resource(name="java:comp/DefaultManagedThreadFactory")
I'm not familiar with Glassfish (I'm a WildFly kind of guy) but you may not see this reference in any JNDI tree display. It may be linked internally to "concurrent/__DefaultManagedThreadFactory" (which is not a resource name btw).
Failing that you can also try
#Resource(lookup="concurrent/__DefaultManagedThreadFactory")
My Tomcat 7 is reporting that there may be a memory leak in my webapp
SEVERE: The web application [/mywebapp] appears to have started a
thread named [pool-1-thread-1] but has failed to stop it. This is
very likely to create a memory leak.
I have a long running task in my webapp that gets initialized when the webapp is started.
public class MyContextListener implements ServletContextListener{
Scheduler scheduler = null;
public MyContextListener(){
scheduler = new Scheduler();
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
scheduler.stop();
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
scheduler.start();
}
}
.. and my Scheduler.java
public class Scheduler {
private final ScheduledExecutorService fScheduler;
public Scheduler() {
fScheduler = Executors.newScheduledThreadPool(1);
}
public void start(){
fScheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
//Perform some task
}
}, 1, 240, TimeUnit.MINUTES);
}
public void stop(){
fScheduler.shutdownNow();
}
}
Even though I calling scheduler.stop(); when shutting down the server, its still reporting there could be a memory leak.
This app is deployed on jelastic.com and I find that once it is started, it runs well for around two days and then the tasks don't seem to be running. There is no exceptions or errors in the logs too.
Am I doing anything wrong here ? Is there really a potential memory leak ?
Calling fScheduler.shutdownNow(); is not enough:
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks.
From JavaDoc.
Instead you must explicitly wait for the tasks that are currently running:
fScheduler.shutdownNow();
fScheduler.awaitTermination(10, TimeUnit.SECONDS);
I believe you should not call the shutdown from the Listener but from the Servlet directly.
contextDestroyed() of the listener is too late for the executor service. As stated in the javadoc All servlets and filters will have been destroyed before any ServletContextListeners are notified of context destruction.
whereas overriding the servlet destroy() should be OK as according to the javadoc This method gives the servlet an opportunity to clean up any resources that are being held (for example, memory, file handles, threads...
#Override
public void destroy( ) {
fScheduler.shutdownNow();
fScheduler.awaitTermination(10, TimeUnit.SECONDS);
super.destroy( );
}