In my Vaadin 8 app running on Tomcat, there should be a background process for refreshing and updating the database. If I use ServletContextListener to have it separate from the main UI, Tomcat won't complete starting up until it finishes executing all instructions in contextInitialized, and since I want to keep it in an infinite loop on a separate thread that calls the database and then sleeps for 5 minutes, the app never actually starts. What would be the correct way to implement this?
3 Answers
If not updating user-interface in Vaadin
Your Question is tagged Vaadin, but seems to be asking only about running a background task without regard for the Vaadin user-interface. If so, you are asking a generic Jakarta Servlet question, not a Vaadin-specific question. Vaadin is just a Servlet, albeit a very large, sophisticated Servlet.
As you noted, writing a class that implements the ServletContextListener
is the place to run code when your web app is launching, before the first user is served, in the contextInitialized
method. And that is the place to run code when your web app is exiting, after serving the last user, in the contextDestroyed
method.
After writing your listener, you must inform the Servlet container (such as Apache Tomcat or Eclipse Jetty) about its existence. The easiest way to do that is by adding the @WebListener
annotation.
package com.example.acme;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
*
* @author Basil Bourque
*/
@WebListener
public class AcmeServletContextListener implements ServletContextListener {
@Override
public void contextInitialized ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is starting. " );
}
@Override
public void contextDestroyed ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is exiting." );
}
}
Do not run your background task using Thread
class. That is old-school. The modern approach uses the Executor framework added later to Java. See Oracle Tutorial.
ExecutorService
To run only one background task, we need a thread pool of only a single thread. Use the Executors
class to instantiate a thread pool.
ExecutorService executorService = Executors.newSingleThreadExecutor() ;
Define your task as a Runnable
or Callable
.
Runnable runnable = new Runnable ()
{
@Override
public void run ( )
{
System.out.println ( "INFO - Acme web app doing some work on background thread. " + Instant.now () );
}
};
You can use the more compact lambda syntax for defining your Runnable
if you wish. I used the long syntax here for clarity.
Tell your executor service to run that runnable.
executorService.submit ( runnable );
A Future
object is returned, as a handle for you to check on the progress or completion of the task. You may not care to use it.
Future future = executorService.submit ( runnable );
Put all that together, plus code to gracefully shutdown our thread pool (the executor service). And we add some timestamps on our console messages with Instant.now()
.
public class AcmeServletContextListener implements ServletContextListener {
private ExecutorService executorService ;
@Override
public void contextInitialized ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is starting. " + Instant.now () );
this.executorService = Executors.newSingleThreadExecutor() ;
Runnable runnable = new Runnable ()
{
@Override
public void run ( )
{
System.out.println ( "INFO - Acme web app doing some work on background thread. " + Instant.now () );
}
};
Future future = this.executorService.submit ( runnable );
}
@Override
public void contextDestroyed ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is exiting. " + Instant.now () );
if ( Objects.nonNull ( executorService ) )
{
this.executorService.shutdown ();
}
}
}
ScheduledExecutorService
If you want to run this task repeatedly, such as every five minutes, do not manage that repetition within your Runnable
or within a Thread
. With regard for separation of concerns, we realize that your background task should focus solely on its main task such as updating the database. Scheduling when that should happen, and how often that should happen, is a different job, to be handled elsewhere.
Where to handle the scheduling? In an executor service purpose-built for that chore. An implementation of ScheduledExecutorService
has methods to run a task once, with or without a delay (a waiting period). Or you can call methods to schedule a task to repeat, say every five minutes.
Similar code to that seen above. We change our ExecutorService
to ScheduledExecutorService
. And we change Executors.newSingleThreadExecutor()
to Executors.newSingleThreadScheduledExecutor()
. We specify an initial delay, and a period for repetition, using the TimeUnit
enum. Here we use TimeUnit.MINUTES
, with an initial delay of 2 (wait two minutes before first run), and a period of every five minutes. If you care to use the Future
, it is now a ScheduledFuture
type.
public class AcmeServletContextListener implements ServletContextListener {
private ScheduledExecutorService executorService ;
@Override
public void contextInitialized ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is starting. " + Instant.now () );
// Instantiate a thread pool and scheduler.
this.executorService = Executors.newSingleThreadScheduledExecutor() ;
// Define the task to be done.
Runnable runnable = new Runnable ()
{
@Override
public void run ( )
{
System.out.println ( "INFO - Acme web app doing some work on background thread. " + Instant.now () );
}
};
// Tell the scheduler to run the task repeatedly at regular intervals, after an initial delay.
ScheduledFuture future = this.executorService.scheduleAtFixedRate ( runnable , 2 , 5 , TimeUnit.MINUTES );
}
@Override
public void contextDestroyed ( ServletContextEvent sce ) {
System.out.println ( "Acme Vaadin web app is exiting. " + Instant.now () );
if ( Objects.nonNull ( executorService ) )
{
this.executorService.shutdown ();
}
}
}
Important tip: Wrap your work in the Runnable within a try-catch to catch any Exception
that might bubble up. If an exception (or Error
) reaches your scheduled executor service, that service will stop all further executions. Your background task stops working, silently, mysteriously. Better to trap all unexpected exceptions (and perhaps errors, that's debatable) and report to your sysadmin, if it is important to you to keep the background task going.
Jakarta Concurrency
If you are deploying to an app server with support for the the Jakarta Concurrency utilities (originally JSR 236), this work gets much easier. You need not write that ServletContextListener
. You can use annotations to have the app server automatically run your Runnable
.
If updating user-interface in Vaadin
Perhaps you want a single background worker that every five minutes updates the display of some of your users. If so, you need a few parts:
- The background thread doing some period work,
- A registry of users’ views to be updated,
- Many instances of the view (Vaadin layout or widget) interested in being updated.
In other words, a limited form of Pub-Sub, publisher and subscriber pattern, with only a single publisher.
A ServletContextListener
implementation is one way to perform work when your Vaadin web app is launching (before serving any users) and when the web app is exiting (after serving the last user). This is a good place to start-up and shut-down your pub-sub publisher and registry.
You can keep a reference to your registry object around globally in the Servlet Context sent to your ServletContextListener
implementation. Use the "attributes" feature, a key-value collection accessed via setAttribute
/getAttribute
/removeAttribute
methods.
If your background worker is running in punctuated periods rather than continuous, learn about the executors framework, specifically the ScheduledExecutorService
. Be sure to gracefully shutdown any such executor service, as it can outlive your web app and even your Serlet container! If using a full-blown Jakarta EE server (such as Glassfish/Payara, WildFly, and such) rather than a mere Servlet container (such as Apache Tomcat or Eclipse Jetty), you may be able to use the Concurrency Utilities feature to more easily run a managed scheduled executor with automatic launch/shutdown.
When you instantiate the view to be updated in your Vaadin user-interface, have that layout or widget register with the registry as being interested in getting updates. Retrieve the registry from the web app’s ServletContext
as discussed in Different ways to get Servlet Context.
I suggest your registry keep weak references to the interested views. Those views will each eventually go away, as the user closes their web browser window/tab. You could program your registered widget to gracefully unregister from your registry as part of its lifecycle. But I suspect using weak references would help make that foolproof. One possibility is using a WeakHashMap
with only keys, and no values, where each key is a weak reference to an instance of your widget/layout registered for updates from your background thread.
To have a background thread update the user-interface of a Vaadin web app, never access the Vaadin widgets from the background thread. Doing so may seem to work at first, but eventually you will have a concurrency conflict and very bad things may ensue. Instead, learn how Vaadin allows an update request to be posted via the access
method by passing a Runnable
. And you will want to learn about Push technology, and how Vaadin makes Push very easy. Notice the section on that page, Broadcasting to Other Users, which describes much the same as this Answer. Along the way, you will likely learn about the benefits and limitations of WebSockets, which can be used automatically by the Atmosphere library leveraged by Vaadin to implement Push.
Throughout all of this, you must become very conscious of concurrency issues and practices, and probably the volatile
keyword. A Java Servlet container is by definition a highly-threaded environment to begin with, and now you will be undertaking your own choreography of those threads. So you will need to read, reread, and study hard the excellent book, Java Concurrency in Practice by Brian Goetz, et al.
After writing all that, I realize now your Question is really too broad for Stack Overflow. But hopefully this Answer helps get you orientated. You can learn more about each piece of the puzzle by searching Stack Overflow. In particular, if you search Stack Overflow, you will find some very long posts by me on these very subjects, with much example code, in Vaadin 8. And consult the Vaadin Forums as well. If this is a vital project with funding, consider hiring the training and consulting services available from the Vaadin Ltd company. Your project is doable; I have done such a project myself along much the same lines as I describe here. It's not simple, but it is possible, and is quite interesting work.

- 303,325
- 100
- 852
- 1,154
-
Thank you so much for the comprehensive answer, Basil. I don't actually need to update the active sessions in real time. Each session can use the database state that is available at the time it starts, and the user can refresh the page to get the updated version. Does that reduce the complexity of the implementation? – Eight Rice Sep 21 '19 at 10:53
-
@AndreiȚăranu Much simpler, then, a subset of what I described. In your `ServletContextListener` Implementation, create your executor service. Keep a reference to it as a member field. Use that executor service to run your background task as a `Runnable` on another thread. Voilà, the thread of your listener is free to continue to completion. In the `contextDestroyed` method of your listener, use the stored reference to the executor service to shut it down as your web app exits. – Basil Bourque Sep 21 '19 at 17:27
The reason Tomcat was waiting for the process to complete is because I was using thread.run() instead of thread.start().

- 816
- 7
- 24
-
Best to **avoid manual use of `Thread`**, especially on an app server. I added a long section to my Answer showing how to use an Executor to easily and gracefully handle your threading. – Basil Bourque Sep 21 '19 at 22:22
@WebListener
public class Application implements ServletContextListener {
// threads
private static ThreadPoolExecutor onDemandExecutor;
private static ScheduledThreadPoolExecutor scheduledExecutorForDisablingAttendanceUpdation;
// thread pools
@Override
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generated method stub
System.out.println("[INFO] Application starting up...");
// thread pools
onDemandExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
System.out.println("[INFO] Application up");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
System.out.println("Application shutting down...");
// shutdown threads
scheduledExecutorForDisablingAttendanceUpdation.shutdown();
onDemandExecutor.shutdown();
// shutdown database connection pool
connPool.dispose();
System.out.println("Application down.");
}
public static ThreadPoolExecutor getExecutor() {
return onDemandExecutor;
}
public static Connection getConnection() throws IOException, SQLException {
// connect();
return connPool.getConnection();
}
}

- 715
- 5
- 7