In The craft
Simple Polling Messaging Queue
The following code is a simple implementation of a Polling service. It has not been optimized for speed nor has it been tested much. It works and shows the concept of a message queue that dynamically loads plugins(dlls) and processes messages.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using DA.Api;
namespace My.Worker.Core
{
public class QueueService
{
/// <summary> Process this object. </summary>
public void Process(string url)
{
IApi api = new Api.Api(url);
string error = null;
bool success = true;
//Retrieving the messages from the Queue
var messages = api.List("get_message_queue_to_process", new { });
//Load all processors found in the /plugins directory
var processors = GetProcessors();
//Process each method
foreach (var message in messages)
{
int messageId = message.Id;
try
{
ProcessMessage(processors, message);
}
catch (Exception ex)
{
error = string.Format("Message:{0}", ex.Message);
success = false;
}
finally
{
//Record success or failure
api.Put("queue/update", new { id = messageId, success, message = error });
}
}
}
/// <summary> Process the message. </summary>
/// Thrown when an exception error condition occurs.
/// The processors.
/// The message.
private void ProcessMessage(IEnumerable processors, Message message)
{
Type processor = null;
Type messageType = null;
foreach (var type in processors.Where(t=> t.FullName == message.MessageProcessor))
{
//discover the processor type
Type single = type.GetInterfaces().Single(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof (IMessageProcessor));
//Discover the message type
messageType = single.GetGenericArguments().FirstOrDefault();
processor = type;
}
if (processor != null)
{
//Create an instance of the processor type
var instance = Activator.CreateInstance(processor);
//Create an instance of the message type and hydrate it with the data from the queue
var imp = GetMessage(messageType, message.Payload);
//Call the process method on the IMessageProcessor and pass in the message
processor.InvokeMember("Process", BindingFlags.InvokeMethod, null, instance, new[] {imp});
}
else
{
throw new Exception(string.Format("Could not find processor {0} implementation. Message Id {1}", message.MessageProcessor, message.Id));
}
}
/// <summary> Gets a message. </summary>
/// Type of the full.
/// The payload.
/// The message.
public object GetMessage(Type messageType, string payload)
{
object implementation = null;
//If message type is null badness has happened
if (messageType != null)
{
//deserialize the message.
implementation = new XmlSerializer(messageType).Deserialize(new XmlTextReader(new StringReader(payload)));
}
return implementation;
}
/// <summary> Enumerates get processors in this collection. </summary>
/// An enumerator that allows foreach to be used to process get processors in this
/// collection.
private static IEnumerable GetProcessors()
{
List implementations = new List();
//Get executing path
Uri assemblyUri = new Uri(Assembly.GetExecutingAssembly().CodeBase);
string path = Path.GetDirectoryName(assemblyUri.LocalPath);
//Find all files in the executing path that reside in the child plugins directory
var files = Directory.GetFiles(path + "plugins", "*.dll", SearchOption.AllDirectories);
foreach (var file in files)
{
var assembly = Assembly.LoadFrom(file);
Type[] types = assembly.GetTypes();
var r = types.Where(type => type.GetInterfaces().Any(i => i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof (IMessageProcessor)));
implementations.AddRange(r);
}
return implementations;
}
}
}