In this article I will show you how to implement a distributed version of the CommonJ WorkManager specification using Terracotta for Spring. This article is a variation of an article that I wrote for TheServerSide.com titled Distributed Computing Made Easy, an article that can be found here.
What is CommonJ WorkManager?
CommonJ is a BEA and IBM joint specification that provides a standard for executing concurrent tasks in a JEE environment. It for example has support for the Master/Worker pattern in its WorkManager API. From BEA's documentation about the specification:"The Work Manager provides a simple API for application-server-supported concurrent execution of work items. This enables J2EE-based applications (including Servlets and EJBs) to schedule work items for concurrent execution, which will provide greater throughput and increased response time. After an application submits work items to a Work Manager for concurrent execution, the application can gather the results. The Work Manager provides common "join" operations, such as waiting for any or all work items to complete. The Work Manager for Application Servers specification provides an application-server-supported alternative to using lower-level threading APIs, which are inappropriate for use in managed environments such as Servlets and EJBs, as well as being too difficult to use for most applications."What we are going to do is to first implement a the specification as a regular single node multi-threaded application, based on the Master/Worker pattern. We are also going to use the Spring Framework and implement the Master, Worker and Shared Queue entities as three different Spring beans;
MyWorkManager
, Worker
and WorkQueue
.
We will then use Terracotta for Spring* to transparently and declaratively, turn this implementation into a multi-node, distributed WorkManager.
Master (WorkManager)
MyWorkManager
bean implements the CommonJ WorkManager interface which has the API that the user uses to schedule Work
and wait for all Work
to be completed. The MyWorkManager
bean does not have any state, and can therefore be configured as a Prototype in the Spring bean config XML file.
Here is how we could implement the work manager bean:
Shared Queue
TheMyWorkManager
bean schedules work by adding work to the WorkQueue
bean, which is a simple wrapper around a java.util.concurrent.BlockingQueue
queue. The WorkQueue
bean is the bean that has state, since it holds the queue with all the pending Work
. We need to have a single instance of this queue that can be available to all workers, and we therefore define it as Singleton in the bean config XML file.
The work queue can be implemented like this:
Worker
Finally, we have theWorker
bean. This bean uses a thread pool to spawn up N number of worker threads that continuously grabs and executes Work from the WorkQueue
. During the processing of the Work
, its status flag is maintained (can be one of either Accepted, Started, Completed or Rejected), this is needed in order for the MyWorkManager
bean to be able to continuously monitor the status of the Work it has scheduled. The Worker
bean does not have any shared state and is configured as a Prototype in the bean config XML file.
This is what a worker bean implementation can look like. As you can see we choose to make use of the Executor
thread pool implementation in the java.util.concurrent
package:
Assembly
These three beans can now be wired up by the Spring bean config file: We now have a fully functional local, multi-threaded, implementation of the CommonJ WorkManager specification.Making the WorkManager distributed
Now comes the hard part right? Well...no. It turns out that in order to turn this implementation into a distributedWorkManager
, all we have to do is to create a Terracotta configuration file in which we declare the Spring beans that we want to share across the cluster:
Done!
Now we have a fully distributed, multi-JVM CommonJ WorkManager.
Client usage
Using the distributed work manager is now simply a matter of getting the bean from the application context and invokeschedule(..)
:
To start up a Worker
you simply have to get the Worker
bean from the application context and invoke start()
:
The usage of the distributed version would roughly be to start up one WorkManager
bean and N number of Worker
beans, each one on a different JVM.
That is all there is to it. Now we have a simple, distributed, reliable, high-performant and scalable CommonJ WorkManager ready for use.
Enjoy.
* RC 1 of Terracotta for Spring was released some days ago (9/12/2006) and is free for production use for up to two nodes.