I have a servlet S which handles callbacks from a 3rd party site.
The callback invocations happen in a specific order. Thus, I need to queue them.
I propos
I second the comment that says managing your own thread pool is a bad idea.
Servlets are for handling HTTP requests. HTTP is a synchronous request/response protocol. The logic for how they're handled belongs somewhere else. That handler may be synchronous or asynchronous, but that should be up to the handler implementation. The servlet should decide which handler to defer to for a given response and that's it.
Even if you use Tomcat or a servlet/JSP engine, you can still use Spring, JMS, and MDPs by adding ActiveMQ to your Tomcat implementation.
Using Listeners I created a ThreadPool that I can integrate with a legacy Tomcat app using the ServletContext to store the ThreadPool and let the listener manage the life cycle so it won't linger.
@WebListener
public class MyThreadPool implements ServletContextListener {
private static final String CONTEXT_ATTRIBUTE = "MyThreadPool";
private ExecutorService myThreadPool;
@Override
public void contextInitialized(ServletContextEvent sce) {
myThreadPool = Executors.newFixedThreadPool(10);
sce.getServletContext().setAttribute(CONTEXT_ATTRIBUTE, myThreadPool);
}
public static ExecutorService getPool(Servlet servlet) {
return (ExecutorService) servlet.getServletConfig()
.getServletContext().getAttribute(CONTEXT_ATTRIBUTE);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
myThreadPool.shutdown();
sce.getServletContext().removeAttribute(CONTEXT_ATTRIBUTE);
}
}
Remember that while your servlets are in seperate threads, they're in the same VM instance, so they're living in a shared memory space. If you create a Singleton instance, it will automagically be shared by all the servlets. You can also create a separate servlet to act as your shared data, which has the advantage that you can use container services to persist it if you want.
There's a thorough examination of ways of doing this --- technically called "servlet collaboration" --- in the OReilly book on servlet programming, available online here.
Oh, one other thought: the one thing you DO NOT WANT TO DO is to try managing your own thread pools inside a servlet container; it can do thread pooling a lot better than you can, UNLESS you mess with it.
This isn't the sort of thing a servlet container is for. You really need a more full-blown J2EE application server if you're going to use a standards-based approach. What you're going to have are hacks otherwise but they might be sufficient for your task.
What I would probably try is creating a DaemonServlet. This is just a normal servlet that is not mapped to a URL (except, perhaps, a blind URL for monitoring purposes, although prefer JMX for this kind of thing). The init()
method is called when the servlet is loaded. You could start a thread in that. Arguably you may need to create two: one that does the work. The other makes sure the first one is running and gracefully terminates it once destroy()
is called.
Alternatively, if you're using Spring (and, let's face of it, what kind of whacko doesn't use Spring?), you could simply create a bean in the application context that does much the same thing, except with Spring lifecycle events (eg afterPropertiesSet() on InitializingBean).
Actually, I have an even better suggestion. Use asynchronous message consumers, which will be a lot cleaner and more scalable but this is predicated on a JMS-based solution, rather than just a LinkedBlockingQueue
(and JMS is probably a better idea anyway). Depending on your constraints, you may not have JMS available as an option however.