Building your own publish/subscribe communication infrastructure - part 1

One of the projects we worked on back in 2007 had a large complex service composition setup. The design quickly introduced point to point integration and tight coupling between services. Ultimately we started to think in publish subscribe patterns, loosely coupled services and broker architecture. We needed a design that in a loose coupled manner handled the interconnectivity between services. The customer was not prepared to buy a $45.000 Biztalk license labeled as an ESB, nor did we have the new Routing Service available in .NET 4.0 back then.

We ended up with designing a publish/subscribe architecture that for filled our requirements in various integration scenarios on the project.

So how do you design a publish subscribe software armed with SQL2005, .NET 3.0, WCF 1.0?

We made the following assumptions about the pub/sub software:

  • Should be able to dispatch generic messages to 1 or more services.
  • Should expose a simple service interface towards the client(s).
  • Must not have any design impact on existing or future services i.e. should be transparent for a receiving service (subscriber) whether it was invoked from our pub/sub software or directly from a client.
  • The client should make no assumption about the subscriber.
  • The client should have a minimum footprint of the routing service interface i.e. really simple interface where you just send a message over the wire.
  • The client operate only on .NET types (or Java types) not angle bracket.
  • Easy service configuration.
  • Support all bindings except for reliable sessions and duplex binding.
  • Must be able to re-send messages in case of failure.
  • Must support most basic security schemes like https and username tokens.
  • Messages must be durable.
  • Subscribers must support metadata (that ruled out REST services back then).

As usual the stakeholders required us to implement all this in a week and under budget of course.

The pub/sub architecture from a 1000 foot view

Build-pubsub-infrastructure-fig1

Very simplistic architecture, it depicts a basic publisher subscriber pattern with simple capabilities to hold configuration data about subscribers, resubmit messages, discover services etc. The result of this rather simple architecture can be viewed in Fig. 2 and Fig. 3

Build-pubsub-infrastructure-fig2

Fig. 2: Here a snippet of the UI, where you discover metadata on a service and setup subscription filters.

Build-pubsub-infrastructure-fig3

Fig. 3: Here you see a message history, when was the message received, which subscribers (if any) received the message, did any errors occurred with the message.

 

Diving into the client interface

From a clients point of view, you deal with a simple interface with one operation taking a CreateRequest message as an argument.

[ServiceContract(Namespace = "http://Esb.ClientPublisher/2007/01/EsbPublisher/")]

public interface IClientEsbPublisher

{

[OperationContract(IsOneWay=true,Action = "Publish")]

[XmlSerializerFormat]

void Publish(CreateRequest message);

}

Note the Publish method is decorated with the XmlSerializerFormat attribute. This will allow us to control the xml programmatically + it instructs the WCF runtime to use the XmlSerializer in favor of the default DataContractSerializer.

The CreateRequest message implementation:

[MessageContract]

public class CreateRequest

{

private XmlElement _resource;

public CreateRequest()

: this((object)null)

{

}

public CreateRequest(object resource)

{

this.Resource = resource;

}

[MessageHeader]

public string ns;

[MessageBodyMember(Order = 0)]

[XmlAnyElement]

public object Resource

{

get { return _resource; }

set

{

Convert c = new Convert();

_resource = c.ObjectToXml(value);

}

}

}

 

We decorate our CreateRequest with the MessageContract attribute, this gives us the freedom to design our own soap envelope in a strongly typed .NET class. The CreateRequest layout is defined by a namespace and a resource, where the namespace (ns) is well the namespace of the Resource you’re publishing, more on this later (note the source code has moved on and provide more options today).

The client is armed with a utility class which helps you resolve a namespace and serialize your .NET object to and XmlElement type before sending the message over the wire.

Publishing a message

The way a client now publishes a message is shown here:

ClientEsbPublisherClient proxy = new ClientEsbPublisherClient("BasicHttpBinding_IClientEsbPublisher"))

Invoice invoiceMsg = CreateInvoice();

XmlElement request = PublisherUtil.ObjectToXmlElement(invoiceMsg);

string targetNameSpace = PublisherUtil.GetNameSpace(invoiceMsg);

proxy.Publish(targetNameSpace, request);

...

 

The basic idea is that a publisher and or a subscriber shared a schema out of band.  In this example here, an Invoice message is published. The invoice is expressed in terms of an XSD (ok,  it could have been defined in a assembly also) and was generated to a concrete .NET type by either using xsd.exe or svcutil.exe.

The utility class PublisherUtil along with a reference to the publisher endpoint is what the client deals with in order to publish messages to the infrastructure. This meets the requirements of leaving a small footprint on the client side and the client operate on a concrete .NET type upon publishing it. From a client’s perspective, we don’t care about the location of the end destination, who receives the message, what to do if error’s happens, what if the receiving endpoint is down for maintenance, switched endpoint address etc.

In part two we dive into the infrastructure where we describe what happens when a message arrives, how is an endpoint that subscribes to a message resolved, what happens in case of failures and a lot more technical tech bits on how to build a publisher subscriber infrastructure.