Reliable message handling for windows Azure.

Requires: Domain Module

Message Handling Feature

Reliable message handling is essential for the enterprise integration and building applications with the Command-Query Responsibility Segregation.

In order to simplify message consumption scenarios, Lokad CQRS App Engine provides Message Handling Feature with the flexible fluent API for its configuration.

While handling messages, infrastructure will take care of:
  • matching incoming messages with their respective handlers, using smart inheritance analysis;
  • constructing transient command handler instances and injecting their dependencies;
  • properly handling all lifetimes and disposing transient components afterwards;
  • running command handlers within the transaction;
  • ensuring that transaction failure is rolled back properly and command is retried later;
  • automatically managing poisons (transferring them to the poison queue for further investigation)
  • automatically dealing with the large messages.

Guidance

Implementation

Message Handling Feature of Lokad CQRS App Engine is implemented as a separate engine process (multiple processes could run simultaneously) that is executed within 1..N threads. This engine process regularly checks for the new messages. Once new message arrives, it is downloaded, matched against the consumers and safely dispatched to them.

This feature depends on the [url:]] feature, which is actually responsible for building up full map of available messages and their consumers.

Configuration

Sample configuration looks like:

builder
// this tells the server about the domain
  .Domain(d =>
    {
      d.InCurrentAssembly();
      d.WithDefaultInterfaces();
    })
  // we'll handle all messages incoming to this queue
  .HandleMessages(mc =>
    {
      mc.ListenTo("sample-01");
      mc.WithSingleConsumer();
    })

See Lokad CQRS Guidance for Sample-01 for more details about this snippet.

Advanced Features

Here's how slightly more advanced configuration might look like:

builder.HandleMessages(mc =>
{
  mc.ListenTo("lokad-command");
  mc.LogName = "Commands";

  // filter out certain message handlers
  mc
    .WhereMessagesInherit<IDomainCommand>()
    .WhereMessages(m => m.Consumer != typeof (SaveMessages));

  // enforce the rule, that message should be dispatched to a single consumer
  mc.WithSingleConsumer();
  // smart polling strategy to reduce number of requests to Azure Queues
  mc.SleepWhenNoMessages = AzureQueuePolicy.BuildDecayPolicy(5.Seconds());
})

Where simple command implementation might look like:
[DataContract]
public sealed class SendMessageCommand : IDomainCommand
{
  public SendMessageCommand(string to, string subject, string body, bool isHtml)
  {
    To = to;
    Subject = subject;
    Body = body;
    IsHtml = isHtml;
  }

  [DataMember] public string To { get; private set; }
  [DataMember] public string Subject { get; private set; }
  [DataMember] public string Body { get; private set; }
  [DataMember] public bool IsHtml { get; private set; }
}

and the corresponding handler for sending email messages from Windows Azure:

public sealed class SendMessageHandler : Handle<SendMessageCommand>
{
  SmtpClient _client;
  string _defaultFrom;

  public SendMessageHandler(ISettingsProvider provider)
  {
    _client = new SmtpClient();
    _defaultFrom = "robot@company.com";
  }

  public void Consume(SendMessageCommand message)
  {
    var mail = new MailMessage();
    mail.To.Add(new MailAddress(message.To));
    mail.Body = message.Body;
    mail.Subject = message.Subject;
    mail.IsBodyHtml = message.IsHtml;
    mail.From = new MailAddress(_defaultFrom);
    _client.Send(mail);
  }
}
Note, that SmtpClient is configured in the application config, which might look like (for Gmail in .NET 4.0):
<system.net>
  <mailSettings>
    <smtp from="user@gmail.com">
      <network host="smtp.gmail.com" port="465" userName="user" password="pwd" defaultCredentials="true" enableSsl="true" />
    </smtp>
  </mailSettings>
</system.net>

Note, that you don't need to inherit from Lokad.CQRS framework interfaces. Domain Module can adapt interfaces declared in your domain assemblies.

Last edited Apr 11, 2011 at 10:32 PM by AlexandrYZ, version 2

Comments

No comments yet.