Using the Internet to solve integration problems can be an adventure. If you've experimented with Internet Web services integration, you know reliability is a big issue. The source of the problem can be anywhere between your potentially unreliable Internet connection and the hosting vendor's possibly overloaded server. You can make network- and Internet-access improvements on your end, but what do you do to fix the vendor's part of the problem?
This article explains an approach for addressing Web service reliability issues. It first introduces a strategy for addressing the problem and then takes a deep dive into the solution.
A Strategy to Mitigate the Problem
The underlying strategy to mitigate the problem is to isolate the Internet Web service code from an application and centralize access to the external Web service so it can be more easily troubleshot and reconfigured. Here are the solution objectives:
- Confine the Web services code to a single place where it can be easily monitored, administered, reconfigured, and troubleshot. Speed is an issue, but it can be sacrificed for robustness.
- Decouple the application from the Internet Web service. Remove Internet Web service code from the application using the Web service. The application should be concerned only with sending and processing the results of the Web service, not with configuration and error handling.
- If the Web service goes down, allow the application to continue functioning normally.
- Make the solution reusable. Multiple Web services will be invoked by many different parts of the application.
Many tools have made invoking a Web service as simple as making a synchronous function call in your application. The key to addressing the Web service reliability issue is abandoning the synchronous function call notion and thinking asynchronously.
Asynchronous messaging is an integration approach extensively covered in the book Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. A complete discussion of asynchronous messaging is beyond the scope of this article, so I'll summarize the key points pertaining to the solution.
In asynchronous messaging, a sender transmits data known as a "message" and a receiver consumes it. A transmitted message moves from sender to receiver through channels. Channels are built using databases, message queues, file systems—anything capable of persisting and sharing data.
A message is composed of two things:
- A header, which contains things like processing instructions, information about the structure of the message, and the ultimate message destination
- A body, which contains the message data
A message can take any physical form: XML, a record in a database, a serialized class, a file, and so forth.
To understand the basic idea behind asynchronous messaging, look at the synchronous Web service example at a high level and examine how asynchronous messaging differs.
When calling a Web service synchronously, the consumer (caller) performs all the following actions in the same running process:
- Gathers values for the Web service parameters
- Locates the Web service
- Connects to the server hosting the Web service
- Calls the Web service
- Handles any errors
- Processes the reply from the Web service
Being synchronous, the actions above take an all-or-nothing approach. All of the actions must happen successively, successfully, and in a timely fashion to complete the process.
Asynchronous messaging is different. Each action or group of actions can be handled by a separate process or class. So, for example, one process may handle collecting and packaging the parameters and then post the packaged parameters to a channel to be picked up by another process that invokes the Web service.
Each class or process is responsible only for performing its assigned segment in the process. Unlike the all-or-nothing approach, a single process cannot fail all segments. If it sounds like object-oriented design, it's because it is like object-oriented design—only on a larger scale.
So, how do you apply an asynchronous message to fix the unreliable Web service problem?
The Asynchronous Message Solution
Applying lessons from the Enterprise Integration Patterns book and using notation from it, Figure 1 shows a design that outlines the solution.
Figure 1. A Design Outlining the Solution
Note the multiple channels, endpoints, and gateways, but only one router. Also note that it uses the database symbol to show that the gateway accesses the database of the application. Another way of expressing this is to use the "Claim Check" symbol.
Using the Figure 1 design achieves the following objectives:
- Decoupling, handling is moved to a specialized Windows service outside of the application
Now, see how the company I work for implemented the design.
Traditional integration projects utilize some piece of middleware or message queue application. The endpoints and channels for my company's service were implemented using Transact SQL and SQL Server. Because my company's applications are all SQL Server-based, SQL Server technologies was a natural choice for easy integration with our application environment.
The technology behind the solution functions as follow:
- Applications write some standard fields to tables (channels) on the server.
- The router reads the table (channel) messages using stored procedures. (The router is a Windows service, and the gateways are all implemented using a .NET interface class inside of a separate assembly.)
Because the router is the heart of the solution, you should focus on the router implementation.
Router: the heart of the solution
The router consists of the classes in Figure 2, which depicts their hierarchical relationship.
Figure 2. Hierarchical Relationship of Router Classes
The classes have the following roles:
- GatewayRouter performs all of the work, reading the channel information and loading/invoking the appropriate XmlServiceGateway contained inside a particular assembly.
- GatewayRouterController spins threads and handles the stopping and starting of the Windows service application.
- GatewayRouterExecution executes the GatewayRouter on one of the controller's threads until the signaling class housed inside the controller signals it to stop.
- ServiceWindowChecker also executes on a thread contained in the controller and continually checks the computer's time. The checker signals other parts of the application when the Windows service has moved out of the service window time. Servers are more likely to be functioning when humans are present monitoring their uptime. A service window function allows you to control when a Web service is invoked.
Channel location information and gateway information are loaded in the config file of the Windows service. You can download the source code, so I'm going to focus only on the key functions in the service.