Message Reliability



Message Reliability

One hundred percent availability is never attainable. That said, there is a lot you can do to get a very high degree of reliability in any messaging system.

With SOAP and Web services, the usual way to get reliability is to use a session, but session technology alone won't give you everything you need to know. What's needed is a way to label messages inside of a session and get acknowledgments that the intended recipient has received certain labeled messages (or all messages). Figure shows the basic idea: Several messages are sent, and an acknowledgment for each message is received.

2. Typical Message Flows

graphics/14fig02.gif

The basic idea is that, within a session, messages are sent and acknowledgments are received. So, at the very least, we need to add to the session header the ability to give a message a number, and also to add acknowledgments. This would look something like Listing 14.8.

Session Header with Message Numbers
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <Session xmlns="http://keithba.com/2002/05/Session">
<Id>uuid:1111-1111-1111-1111</Id>
<MessageNumber
           xmlns="http://keithba.com/2002/04/Reliable">
          4
     </MessageNumber>
     <Ack xmlns="http://keithba.com/2002/05/Reliable">
          3
      </Ack>
      <Ack xmlns="http://keithba.com/2002/05/Reliable">
          1
     </Ack>
 </Session>
</soap:Header>
  <soap:Body>
    ...
  </soap:Body>
</soap:Envelope>

Notice that in Listing 14.8, both message 1 and message 3 are being acknowledged at the same time. There is nothing to stop this from occurring.

In fact, in a long running conversation between two message endpoints, it would be unusual for there always to be a pair set of messages that could be acknowledged.

Notice that message numbering and acknowledgment are achieved by extending the session header that we defined earlier. The schema says that these extensions need to be in a namespace other than the session name-space; therefore, in this case, we are using http://keithba.com/2002/05/.

In addition to the <MessageNum> and <Ack> elements, it would be useful to be able to request an acknowledgment. You can accomplish this by adding one more element, <RequestAck>, whose value is a message number. Listing 14.9 shows the addition of this element.

Listing 14.9 Adding the <RequestAck> Element to the Session Header
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
 <Session xmlns="http://keithba.com/2002/05/Session">
 <Id>uuid:1111-1111-1111-1111</Id>
<MessageNumber
           xmlns="http://keithba.com/2002/04/Reliable">
          4
     </MessageNumber>
     <Ack xmlns="http://keithba.com/2002/05/Reliable">
          1
     </Ack>
     <RequestAck
       xmlns="http://keithba.com/2002/05/Reliable">
          3
     </RequestAck>
 </Session>
</soap:Header>
  <soap:Body>
    ...
  </soap:Body>
</soap:Envelope>

Figure illustrates the message flow with this capability. Notice how loosely coupled the entire system in Figure appears to be. The request–response semantic of typical RPC systems is completely missing. Instead, the acknowledgment and request for acknowledgment semantic allows for a much more robust yet flexible system. It is more robust because now at least one process will always be aware of any errors or data loss.

3. A Message Flow with Acknowledgments and Requests for Acknowledgment

graphics/14fig03.gif

The schema for these additional elements is simple:

<xs:schema 
     targetNamespace="http://keithba.com/2002/05/Reliable"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns="http://keithba.com/2002/05/Reliable"
     elementFormDefault="qualified"
     attributeFormDefault="unqualified">
          <xs:element name="MessageNum" type="xs:integer"/>
          <xs:element name="RequestAck" type="xs:integer"/>
          <xs:element name="Ack" type="xs:integer"/>
</xs:schema>

The modified class for session would now look like Listing 14.10.

Additional Classes
[XmlRoot(Namespace="http://keithba.com/2002/05/Session")]
public class Session : SoapHeader
{
     private String _Id;
     public String Id
{
     get
     {
         return _Id;
     }
     set
     {
         _Id = value;
     }
}

private Initiate _Initiate;
public Initiate Initiate
{
     get
     {
         return _Initiate;
     }
     set
     {
         _Initiate = value;
     }
}
private Terminate _Terminate;
public Terminate Terminate
{
     get
     {
         return _Terminate;
     }
     set
     {
         _Terminate = value;
     }
}
private int _MessageNum;
[XmlElement(
 Namespace="http://keithba.com/2002/05/Reliable")]
public int MessageNum
{
     get
     {
         return _MessageNum;
     }
     set
     {
         _MessageNum = value;
     }
}
private int[] _Ack;
     [XmlElement("Ack",
      Namespace="http://keithba.com/2002/05/Reliable")]
     public int[] Ack
     {
         get
         {
             return _Ack;
         }
         set
         {
             _Ack = value;
         }
     }
     private int[] _RequestAck;
     [XmlElement("RequestAck",
      Namespace="http://keithba.com/2002/05/Reliable")]
     public int[] RequestAck
     {
         get
         {
             return _RequestAck;
         }
         set
         {
             _RequestAck = value;
         }
     }
}

The application code for handling this varies depending on how durable the conversation needs to be, but typically you will want to involve a database of some kind. Using this database, store the messages received. As the application processes each one, send an acknowledgment. If the application receives a request for an acknowledgment, that message can then be processed immediately if at all possible.