Asynchronous Workloads with WebSphere Application Server

Jul 26, 2014
5 minute read

So I’ve been using WebSphere for a while now, and continue to discover new functionality in this powerhouse of an application server. This post focuses on performing background work in WebSphere Application Server (WAS) 7.0, which is an EE 5 compliant container.

Firstly a quick outline of the problem. Across a series of web service calls, there exist a number of intensive processes that need to take place. I wanted a way to perform work this asynchronously somewhere else within the application server, without being bound to the request/response cycle that HTTP web services impose…in essence making the actual service calls appear super snappy.

My initial instinct was to look at leveraging JMS (messaging) and a stateless EJB (business component). But this seemed to involve way too much manual plumbing. The EJB 3.1 spec eliminated most of this boilerplate plumbing with the introduction of the @Asynchronous annotation. Sadly wasn’t an option for me here with WebSphere 7.0, which only supports EJB 3.0.

A work manager is a thread pool created for Java Platform, Enterprise Edition (Java EE) applications that use asynchronous beans. Using the administrative console, an administrator can configure any number of work managers. The properties of the work manager are defined, including the Java EE context inheritance policy for any asynchronous beans that use the work manager, and the binding of each work manager to a unique place in Java Naming and Directory Interface (JNDI).

Work managers can be found in the WAS adminstration console tucked away under the Resources > Asynchronous beans > Work manager left navigation menu.

Behaviours of the work manager can be tweaked through the WAS admin console (or programmatically via the management API), and includes options such as the work timeout, the request pipeline size, thread pool sizing, and more:

The Work Manager API has been around for yonks, and provides really powerful out of the box functionality:

A managed pool of processes, ready to do your heavy lifting, configurable through the WebSphere management interface.

Intelligent context propagation. The process you are allocated is passed the relevant classpath information, transactional state, security context, and so on. In essence, you can assume the container will perform the work as if the work manager is running within your current Web context. But the magic is, its truly a independent process of it own.

While the underlying mechanics are complex, actually using this API is rather simple. When you want your Web module to perform an action, you create an implementation of the Work interface and submit that instance to the work manager. The work manager daemon creates another thread, which invokes the run method of your Work implementation. Hence, using a thread pool the work manager can create threads for as many Work implementations submitted to it. Not only that, the work manager takes a snapshot of the current Java EE context on the thread when the work is submitted.

To demonstrate, the following three classes from com.ibm.ws.runtime.jar (lib directory of your WebSphere installation, e.g. C:\IBM\SDP\runtimes\base_v7\plugins\com.ibm.ws.runtime.jar) Work, WorkManager, and WorkItem are required.

OK, so to kick things of a simple SOAP web service, with operation sayHello.

Since we want to exercise the Work Manager from a Web Module, it is treated as any other container provided resource (e.g. a JDBC Data Source) and a resource binding must be registered in your web.xml and ibm-web-bnd.xml configurations:

javax.naming.NameNotFoundException: Name comp/env/wm not found in context "java:".
at com.ibm.ws.naming.ipbase.NameSpace.getParentCtxInternal(NameSpace.java:1837)
at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1166)
at com.ibm.ws.naming.ipbase.NameSpace.lookup(NameSpace.java:1095)
at com.ibm.ws.naming.urlbase.UrlContextImpl.lookup(UrlContextImpl.java:1233)
at com.ibm.ws.naming.java.javaURLContextImpl.lookup(javaURLContextImpl.java:395)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:220)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:160)
at javax.naming.InitialContext.lookup(InitialContext.java:436)
at net.bencode.fooservice.FooServiceSOAPImpl.scheduleWork(FooServiceSOAPImpl.java:45)
at net.bencode.fooservice.FooServiceSOAPImpl.sayHello(FooServiceSOAPImpl.java:24)

Using an HTTP test client, such as soapUI, can see the WAS server returns the response very quickly (e.g. 19ms in this instance):

Meanwhile, I can see the WAS application server happily carrying on with processing in the background.