14 May 2013

Pub/Sub Implementation I -- Common Components

After explaining what I plan to build (last time) now it's time to build it out.  This will be very rough around the edges; it's more an exercise to see whether or not this idea has legs enough to be worth spending more time on.

So, if we're going to do this (even rough), let's do it more-or-less right.  That means starting with our common components.  We're going to define our two Interfaces IPublisher<T> and ISubscriber<T> and our base Message type.  Next, we'll define our MessageBox (I called mine "Broker" but "MessageBox" is more appropriate).  Finally, we'll define our final message types.

Here's IPublisher
public interface IPublisher<T> where T: Message
{
  T CreateMessage();
  bool Publish(T message);
  bool Publish(IEnumberable<T> messages);
  Task<bool> PublishAsync(T message);
  Task<bool> PublishAsync(IEnumerable<T> messages);
}

That's the easy one.  It can create a message of its appropriate type, and it can publish a single message or a group of messages.  The "Task<bool>" declarations are to take advantage of the new Async features in .NET 4.5, if we want.

Here's ISubscriber
public interface ISubscriber<T> where T: Message
{
  IList<T> PendingMessages {get; set;}
  IList<T> ProcessedMessages {get; set;}
 
  IList<T> GetMessages();
  IList<T> FilterMessages(Func<T, bool> predicate);
  Task<IList<T>> GetMessagesAsync();
}

This one defines two properties, in addition to its three methods.  It has to be able to get messages, Filter them, and (as the properties suggest) take them from "pending" to "processed."

I did not define a "Process" method, however, because each system will have different requirements for how it does that.  Maybe it just takes it's PendingMessages as is, or maybe it also accepts some parameters, or whatever.

Next, we'll take a look at some of our Message types.  Not all of them, just some.

First, the base Message class.
public abstract class Message
{
  public string Id {get; set;}
  public string Publisher {get; set;}
  public DateTime PublishedDate {get; set;}
 
  public override bool Equals(object obj)
  {
    if(obj == null) return false;
    if(obj is Message)
    {
      var msg = obj as Message;
      return (this.Id == msg.Id);
    }
  }
 
  public override int GetHashCode() 
  {
    return base.GetHashCode();
  }
}

Here, you see we're defining a string "Id" (that's because I'm using RavenDB as my database for this example- you could do it differently), a string "Publisher," and a DateTime "PublishedDate."  Those are things all of my messages will have in common- Which message am I, who created me, and when did they do that?  I've also overridden Equals.  It's possible I'll have the same message coming from two different requests to the DB- that would create two different instances that are identical- rather than leaving the base Equals, I have specified "Hey, no two of us can have the same Id."

That's enough for now.  Next time: The MessageBox (Broker).

No comments:

Post a Comment