Aug 28

One of the first applications we built with MassTransit provides messaging for a long-running transaction started by an application submitting a request. The request is formatted into a X12 envelope and sent to a web service. An intermediate response is returned (a X12 997) with a correlation identifier for the request. Another web service is polled for the response, which can be the result or an indication that the request is still pending. When the response is received, the X12 document is translated and stored in the database. Finally, the user is notified that the transaction is complete and the result is displayed.

As work proceeded on this application, I started to recognize the need for something to coordinate the different steps in a transaction involving multiple loosely-coupled services. Due to the duration of these transactions (the example above can take anywhere from three to sixty seconds), it is unreasonable to keep a single System.Transactions style transaction open the entire time. I started researching how others approached the problem and found a couple of articles that helped. After reading Sagas by Hector Garcaa-Molrna and Kenneth Salem (© 1987 ACM, PDF) and the chapter on sagas in the upcoming book Practical SOA by Arnon Rotem-Gal-Oz (PDF), I started to think about how this could be implemented within MassTransit.

I should note that NServiceBus (another open source service bus) also supports sagas, but I purposely avoiding taking a look at how Udi Dahan implemented them. Once saga support in MassTransit is complete I plan to review the source for NServiceBus to see how the implementations differ. I spoke with Udi at ALT.NET Seattle and his writing has been both educational and inspirational. A lot of great discussions in the NServiceBus mailing list have been an excellent resource as well.

So after a few weeks of trying to flesh out the structure (using TDD, of course), I finally arrived at what I think will be a highly usable infrastructure for handling sagas. In the project MassTransit.Saga.Tests, I’ve created a test that simulates a user registering for a web site. The class for the registration is shown below.


public class RegisterUserSaga :
	InitiatedBy< RegisterUser >,
	Orchestrates< UserVerificationEmailSent >,
	Orchestrates< UserValidated >,
	ISaga< RegisterUserSaga >
{
	private string _displayName;
	private string _email;
	private string _password;
	private string _username;

	public RegisterUserSaga(Guid correlationId)
	{
		CorrelationId = correlationId;
	}

	public Guid CorrelationId { get; private set; }
	public IObjectBuilder Builder { get; set; }
	public IServiceBus Bus { get; set; }
	public Action< RegisterUserSaga > Save { get; set; }

	public void Consume(RegisterUser message)
	{
		_displayName = message.DisplayName;
		_username = message.Username;
		_password = message.Password;
		_email = message.Email;

		Save(this);
		Bus.Publish(new SendUserVerificationEmail(CorrelationId, _email));
	}

	public void Consume(UserVerificationEmailSent message)
	{
		// once the verification e-mail has been sent, we allow 24 hours to pass before we
		// remove this transaction from the registration queue
		Bus.Publish(new UserRegistrationPending(CorrelationId));
		Bus.Publish(new UpdateSagaTimeout(CorrelationId, TimeSpan.FromHours(24)));
	}

	public void Consume(UserValidated message)
	{
		// at this point, the user has clicked the link in the validation e-mail
		Bus.Publish(new UserRegistrationComplete(CorrelationId));
		Bus.Publish(new CompleteSaga(CorrelationId));
	}
}

At the top of the class, the messages consumed by the saga are specified. InitiatedBy indicates the message initiates a new instance of the saga. Orchestrates is for messages that are part of the saga once it has been initiated. All saga instances are identified by a Guid and all messages consumed by the saga should have the CorrelatedBy< Guid > interface. A saga must also implement the ISaga generic interface to allow certain properties to be set giving the saga instance access to the bus and the object builder.

Once the saga class is added to the bus (via the AddComponent method), any messages consumed by the saga will be dispatched to the saga instance. A generic ISagaRepository must also be registered in the container so that sagas can be persisted between messages. The saga dispatcher uses the repository to either load or create the instance of the saga. Since instances of the saga class are saved, the class can expect the members to also be persisted between messages allowing state to be retained.

There is still some work to be done, including a service to handle timeouts and retries. It will be up to the developer to handle any compensating actions that need to be taken in the case of a failure. Therefore, it is highly suggested that the saga also consume any Fault< T > messages that are published when a message consumer throws an exception — particularly if the consumer is not part of the saga (such as an application or domain service).

The code is currently in the trunk and slated to be part of the 0.3 release.

Aug 22

I was reading through the Xgrid documentation for OS X yesterday after reading an article on Integrating Xgrid Into Cocoa Applications. The article gave me some ideas and I decided to see what it would take to build a distributed processing system on top of MassTransit. The result is a new MassTransit.Grid namespace that includes support for building distributed task processing into an application. The following sections define the language used in the distributed task classes.

Distributed Tasks

A distributed task contains one or more subtasks that need to be processed concurrently across multiple systems. To create a distributed task, create a class that implements IDistributedTask. The input and output types for the subtasks must also be defined by the distributed task class.


public interface IDistributedTask< TTask , TInput, TOutput >
{
    int SubTaskCount { get; }
    TInput GetSubTaskInput(int subTaskId);
    void DeliverSubTaskOutput(int subTaskId, TOutput output);
    void NotifySubTaskException(int subTaskId, Exception ex);
    void WhenCompleted(Action<ttask> action);
}

Subtasks

A subtask is an individual unit of work within a distributed task. Each subtask should be completely standalone and not depend upon the completion of any other subtask within the distributedtask. There is no attempt to execute the subtasks within a distributed task in order. A subtask has specific input and output types, each of which are defined by a class (POCO style). These input types are used to determine which workers are used to process the subtasks.

DistributedTaskController

To insulate the application from the details of coordinating the subtasks, a generic DistributedTaskController is used. This class is built from the class that implements IDistributedTask, along with the input and output types. Once created, the application can call .Start() to being processing the distributed task. The controller performs any initial identification of workers that are available to process the subtasks, along with the coordination to ensure that workers are not overloaded.


public class DistributedTaskController< TTask , TInput, TOutput >

TTask is the class that implements IDistributedTask, TInput is the subtask input type, and TOutput is the subtask output type.

Workers

To make it easy to create workers to handle subtasks, a default worker implementation is available. This worker handles the coordination with the DistributedTaskController, along with the delegation of the messages to the actual subtask worker. For example, a worker that accepts a GenerateFileHash object and outputs a FileHashGenerated object would be setup as shown:


public class FileHashGenerator :
       ISubTaskWorker<  GenerateFileHash , FileHashGenerated >
   {
       public void ExecuteTask(GenerateFileHash input, Action< FileHashGenerated > output)
       {
           string path = input.Path;
 
           // do work here
 
           output(new FileHashGenerated());
       }
   }

The worker can then be added to the container for servers that will be processing the subtasks using:


_container.AddComponent<  FileHashGenerator >();
_bus.AddComponent< SubTaskWorker < FileHashGenerator, GenerateFileHash, FileHashGenerated > >();

This will register the SubTaskWorker for the worker as a message handler for the messages that are used on the transport to transfer the input and output data between the controller and the subtask workers.

Exception Handling

If an exception occurs in a subtask, the worker and controller leverage the built-in fault handling support of MassTransit to notify the distributed task that an exception has occurred. The controller will call the NotifySubTaskException method with the subTaskId and the exception that was thrown by the worker allowing the distributed task to determine the next course of action based on that failure. Options would include simply aborting the distributed task, fixing the input data and adding it to the end of the subtask list, or some other application-defined behavior.

Dynamically Adding Subtasks

To reduce the impact of setup time on the overall duration of a distributed task, it is not necessary to have all of the subtasks loaded before starting the distributed task. This also allows additional subtasks to be added based on the output from other subtasks. For example, a task to parse a remote file system may identify additional folders that need scanned for content. The distributed task could just add those folders to the end of the subtask list and they would be picked up by the controller. By allowing this, the distributed task is responsible for calling the delegate set by the controller to indicate that all of the subtasks have completed. The DistributedTaskController will then release any resources that were in use.

Sample in Unit Tests

A quick sample was built in the unit tests (MassTransit.Grid.Test) that shows an integer factoring service. The distributed task creates a bunch of very large integers and processes them as a distributed task between the workers that are available. Hopefully this demonstrates how the classes are hooked together since this was used to drive out the feature set.

Wrapping Up

This is just a brief introduction to the distributed processing capabilities that were added to MassTransit. There are likely some additional features to add that will hopefully be identified as the feature it put to use. Therefore, it is important to note that this feature is still in development and should go through some considerable testing before putting it into use in a production application. Any feedback is always welcome (including patches) so try it out!

Aug 17

When deploying an application, it is important to consider how the application performance will be monitored. For interactive applications, this may include measurements such as the time to load a page, how long it takes the page to be ready for user input, or even how much data is transferred to the client on each request. In the case of a service, it may be important to know the duration for individual transactions, a batch of transactions, or another unit of work.

The benefits of being able to measure the performance of an application are numerous. First, it helps to track performance over time as updates are made to the application. If a new version of the application “feels slower” to users, the developers would be able to compare the performance of the current version to the previous version. This will either identify where the system has degraded or (unlikely as it may be) show that the user is just mistaken.

Another benefit of knowing the performance criteria for an application related to service-level agreements. If the response time of an application can be measured, those metrics can be used to establish expected performance numbers to share with customers. For example, if a certain operation takes less than two seconds on 97% of all requests, customer expectations could be set using that information. Without accurate measurement, it would be impossible to answer that type of question.

An Example

An customer service application has a feature that submits user input to a remote service. When the user clicks submit, a request is built containing the user input and credentials retrieved from the customer configuration. The request is then sent to the remote service. When the response is received, the data returned is formatted for display and shown to the requesting user.
Within this example, there are several points that could be measured.

  • The overall duration of the request from the time the user clicks submit until the response is displayed could be tracked. This would be useful in tracking the overall user response time.
  • The time taken to retrieve the credentials from the configuration store could be tracked. This would help identify a slowdown in the database (or whatever type of storage is being used).
  • The elapsed time between sending the request to the remote service and receiving the response could be measured. This would help identify latency issues with the remote service.

All of these values could also be compared to each other to separate the total time for the operation into the amount of time for each individual operation.

Method Timer

To measure a method on a class, a stopwatch can be used to measure the elapsed time of the method. To make it easy, I created a class that encapsulates the functionality of the Stopwatch class (from the System.Diagnostics namespace). My class implements IDisposable, allowing it to be automatically disposed at the end of the function with a using {…} block.


public string LoadUpdates(string url, string name)
{
    using (AutoFunctionTimer timer = new AutoFunctionTimer(url, x => _log.Info(x)))
    {
        string updatePage;
        using (timer.Mark())
            updatePage = new PageLoader(url).GetBody();
        using (timer.Mark())
            return GetUpdates(name, updatePage);
    }
}

The delegate specified on the constructor is called when the stopwatch is disposed and the timing measurements are complete. The delegate is passed the stopwatch so that it can be output to a log file for processing by the measurement code. The string output includes the time the method started (in UTC), the duration of the method, and the string passed to the constructor.

Timer Sections

Sections make it possible to measure individual operations within a method. The time for each section can be logged, making it easy to identify the largest time consumers in a method. In the code example above, the timer.Mark method is used to create a section. This section time is then output after the total time, allowing it to be compared to the duration of the method. If multiple sections are created, they are output in creation order for consistency.

The code for the entire class is shown below.


namespace MyNamespace.Core
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Text;

    public class AutoFunctionTimer : IDisposable
    {
        private readonly Action<string> _action;
        private readonly string _description;
        private readonly List<stopwatch> _marks = new List</stopwatch><stopwatch>(10);
        private readonly Stopwatch _stopwatch;
        private DateTime _started;

        public AutoFunctionTimer(string description, Action<string> action)
        {
            _description = description;
            _action = action;
            _started = DateTime.UtcNow;

            _stopwatch = Stopwatch.StartNew();
        }

        public void Dispose()
        {
            _stopwatch.Stop();

            _action(ToString());
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder(256);

            sb.Append(_started.ToString("yyyy-MM-dd HH:mm:ss ")).Append(_stopwatch.ElapsedMilliseconds);

            foreach (Stopwatch mark in _marks)
            {
                sb.Append(' ').Append(mark.ElapsedMilliseconds);
            }

            if (!string.IsNullOrEmpty(_description))
                sb.Append(" ").Append(_description);

            return sb.ToString();
        }

        public CheckPoint Mark()
        {
            Stopwatch watch = Stopwatch.StartNew();
            _marks.Add(watch);

            CheckPoint point = new CheckPoint(watch);

            return point;
        }

        public class CheckPoint : IDisposable
        {
            private readonly Stopwatch _stopwatch;

            public CheckPoint(Stopwatch stopwatch)
            {
                _stopwatch = stopwatch;
            }

            public void Dispose()
            {
                _stopwatch.Stop();
            }
        }
    }
}

Logging Performance Metrics

For measuring performance within a single application or service, I recommend using log4net to output performance metrics to a file. It’s easy to setup and configure post-deployment, making it an obvious choice. Additionally, each server should log to a directory on the local drive. Not only does this eliminate the need for a network share and the associated permissions, but it makes it less likely that network latency will impact system performance due to logging.

For distributed applications, the story changes quite a bit. Because of the nature of distributed operations, I’ll cover them in another post.

Jul 07

Over the past few weeks, Dru and I have been working on the next release of MassTransit. The current release (0.2) has been beat on pretty hard and is currently seeing some active use in the field. There were a few tweaks made after the initial 0.2 drop to address some issues that popped up.

One of the really cool new features coming in the next release is the ability to automatically wire publishing into the consumers. By implementing a new interface, the service bus will automatically attach the appropriate plumbing into the consumer at the time of creation to handle the publishing of messages back out of the consumer. The new Produces<T> interface helps to insulate your code from the IServiceBus interface by relying only on the new interface on your message handler class.

For example, take a look at the following class:

public class OrderService :
Consumes<createorder>.All,
Produces<ordercreated>
{
private Consumes</ordercreated><ordercreated>.All _orderCreatedConsumer;

public void Consume(CreateOrder message)
{
/* Do the order work here */
_orderCreatedConsumer.Consume(new OrderCreated());
}

public void Attach(Consumes</ordercreated><ordercreated>.All consumer)
{
_orderCreatedConsumer = consumer;
}
}

The ServiceBus will automatically call Attach() to connect a publishing consumer to the class when it is created from the container (so this only works with AddComponent<> style message handlers). These helpers classes will take the call to Consume(new OrderCreated()) and route it through the bus and out to any subscribed consumers without knowing about the actual bus itself. This also makes it easy to use the same message handler with multiple IServiceBus instances if you are listening to multiple endpoints.

This is just one of the new things coming soon that I’m pretty excited about. There are a few others, but that will be the subject of a later post.

Jun 13

We’ve dropped a new release of MassTransit today, version 0.2 is now available on the main page. There are several new features included in this release. It was great to get some feedback from people who have tried MassTransit, along with the evolution from discussions with Greg Young, Udi Dahan, Ayende, and others at ALT.NET Seattle.

A quick summary of the changes in this release:

Extensible Message Dispatcher

To make it easy to add new messaging patterns to the service bus, MassTransit has an entirely rewritten message dispatcher. The new code is structured in a producer/consumer style that lends itself to easy extensibility, allowing new features such as batch messaging and correlated messages without heavy lifting.

Component-Based Message Handling

In the previous version, handling messages required an object to subscribe to messages types passing methods to handle the messages. Now, a class can implement interfaces to support message consumption and the class itself can be added to the service bus. The service bus will then create objects to handle each message, removing the need to use the same instance for each message received. A class can handle multiple messages types, and can also indicate whether to receive all, selected or correlated messages by implementing the Consumes.All, Consumes.Selected, or Consumes.For interface.

Batch Messaging

The new message dispatcher includes support for message batches. Instead of having to correlate a batch of messages at the application layer, an object or component can consume a batch instead of each individual message. Details of how to use batch messaging are on the wiki.

Container Integration

We finally bit the bullet and started using a container. A new assembly called MassTransit.WindsorIntegration adds a default container derived from WindsorContainer that adds facilities to create ServiceBus instances. A new custom syntax was created to make it easy to configure multiple ServiceBus instances. All of the samples have been updated to use the new container to help understand the integration points.

Plain Old C# Object Message Objects (POCOMOs Anyone?)

The need to have all messages implement IMessage is gone, reducing the footprint of MassTransit in your application code. There are some new interfaces to handle things like correlated messages and batch messages, but those are only needed to use the built-in support for those message patterns.

Better Thread Management

To allow for more control over resources, a new thread manager has been added. While we haven’t exposed the thread configuration yet, a dedicated thread pool for asynchronous message dispatching should allow for more efficient message handling. We also took all the threading code from the endpoint and put it in the service bus, reducing the complexity required for new endpoints. In fact, the endpoint structure has also been redesigned to be more send/receive focused.

Publish/Subscribe Focus

The service bus now has a pure publish/subscribe architecture compared to the previous additional methods, such as Send() and Request(). For applications that need to send messages directly to endpoints, the endpoint now has a Send() method. The publishing of messages takes advantage of the same new subscription code, allowing all messages type information to be cached for better performance (avoiding the reflection penalty on each call to Publish). With the extensibility of the message dispatcher, it’s likely that remote endpoints may some day find there way into the dispatcher, resulting in a single dispatch engine for asynchronous publishing of messages as well.

Request/Reply

Requests are handled in an entirely new way, using a new fluent builder. The fluent builder allows the calling code to subscribe to any responses (directed via the Consumes.* interfaces, indicate whether an asynchronous callback should be allowed (for [WebMethod] style Begin/End usage, PageAsyncTask usage, or MonoRail asynchronous actions), and get a future object that can be used to complete the request upon receipt of a response. The responses are handled by the calling class itself, the future object is used to signal the operation complete which will release any waits or callbacks for the action.

Distributed Subscription Cache

A new distributed subscription cache (backed by memcached) is now available. This is mostly designed for high volume request/reply applications that need to add and remove a lot of correlated subscriptions and maintain a high level of performance. A load test will be added to the HeavyLoad sample soon, but it seems to hold up pretty well so far under regular testing.

Dashboard

Dru has been hard at working making an operations dashboard part of the core product. One of the big things about messaging systems is being able to assess the health of the endpoints at any time. The goal of the dashboard is to provide that single pane of glass to find out which endpoints are alive, what messages they are handling, and indicate any problems to the viewer. There are many plans for this, including the ability to remotely control the endpoints for dynamic adjustments to load handling and perhaps even remote service restarts.

Deployment

Dru has also been working on the deployment story, making it easier to deploy MassTransit into a production system. There is much love needed there, but I’m hoping to dig into it soon to see how things have gotten easier to manage.

I’m sure there are many more features that have been added under the covers. The main thing is that with this release (0.2) we’re pretty happy with the API experience. The consumer code is easy to understand and implement, particularly compared to the earlier version. It is unlikely that we’ll do another major overhaul to the interface like we did with this version.

So give it a shot, and blog about your experiences!

Jun 02

This past couple of weeks I’ve been putting some serious time into MassTransit. My primary goal is to improve the internal architecture and remove some of the MSMQ leaks into the infrastructure. Our original goal was to stick purely to MSMQ, however, as we got more into messaging systems we found that there are a lot of other transports with different advantages. For example, using ActiveMQ would make it easy to add integration with Java applications down the line. The problem at this point was all the code designed around MSMQ was making it difficult to support other transport types.

About two weeks ago, I started working on a completely new method of dispatching messages within the service bus. My goal was to support a pure producer/consumer model using a publish/subscribe pattern. With this in mind, I built a new message dispatcher that allowed for a new way of specifying message subscriptions. Previously to this change, a service interested in messages would do the following:

_bus.Subscribe<MyMessage>(MyHandlerMethod);
public void MyHandlerMethod(IMessageContext<MyMessage> context) {}

Because of this structure, there had to be an instance of the class in memory and it somehow needed to be started so that subscriptions could be added. The class also needed to be stopped so that it could remove any subscriptions from the service bus. Another goal was to be able to use an object builder to create objects as needed to handle messages. For example, we wanted to use Castle Windsor to dynamically build objects to handle messages and get all the injection benefits of the container.

To support this new style, I added some new interfaces and made it possible to register either an object or a class with the service bus. As an actual example, compare the original subscription client code to the new version:

Before the changes:

public class SubscriptionClient : IHostedService
{
	public void Start()
	{
		_serviceBus.Subscribe<AddSubscription>(HandleAddSubscription);
		_serviceBus.Subscribe<RemoveSubscription>(HandleRemoveSubscription);
	}
	public void Stop()
	{
		_serviceBus.Unsubscribe<AddSubscription>(HandleAddSubscription);
		_serviceBus.Unsubscribe<RemoveSubscription>(HandleRemoveSubscription);
	}
	public void HandleAddSubscription(IMessageContext<AddSubscription> ctx)
	{
		_cache.Add(ctx.Message.Subscription);
	}
	public void HandleRemoveSubscription(IMessageContext<RemoveSubscription> ctx)
	{
		_cache.Add(ctx.Message.Subscription);
	}
}

And now after the changes:

public class SubscriptionClient : IHostedService,
	Consumes<AddSubscription>.All,
	Consumes<RemoveSubscription>.All
{
	public void Consume(AddSubscription message)
	{
		_cache.Add(message.Subscription);
	}
	public void Consume(RemoveSubscription message)
	{
		_cache.Remove(message.Subscription);
	}
	public void Start()
	{
		_serviceBus.Subscribe(this);
	}
	public void Stop()
	{
		_serviceBus.Unsubscribe(this);
	}
}

The code just makes more sense and is easier to understand after the changes. In addition, you can also just call _bus.AddComponent<T>(); to register a type with the service bus and it will use the object builder to create an instance of the class to handle the message. If you’re using a container like Windsor, you can specify the lifestyle of the object(s) there, either singleton, transient, or pooled — depending upon your application requirements.

Also notice that there are various types of consumers supported, indicated by the interface used in the consuming class. Consumes<T>.All will deliver any message of type T to the consumer. Consumes<T>.Selected adds an Accept(T message) method to the class to screen any messages before removing them from the endpoint (at least with MSMQ, likely not the case with ActiveMQ).

The third option presently available is Consumes<T>.For<V> and adds support for a correlated consumer. In previous versions of MassTransit, Request/Reply was handled by using the transport message identifiers and setting a correlation identifier on the transport message. This leaked a lot of details into the service bus layer that were not pretty. Instead of using the transport correlation identifier for messages, we decided to add a new interface that messages can implement called CorrelatedBy<V>. This interface has a single method that returns the correlation identifier for the message — and it is expected that the message body itself will contain the correlation identifier.

So now a request/reply pattern would look something like this:

class Controller : Consumes<Response>.For<Guid>
{
	public void Consume(Response message)
	{}
	public void Action()
	{
		_actionId = Guid.NewGuid();
		_bus.Subscribe(this);
		_bus.Publish(new Request(_actionId, someValue, someValue2);
	}
}

When the object subscribes to the bus, the correlation identifier is used to filter incoming messages so that only correlated messages are delivered to the object. This is cleaner from a interface contract perspective since you can look at a service and see what messages are produced and ensure that your controller implements all of the expected responses.

While working on these API changes, I also made a number of other changes including:

  • Messages no longer need to implement IMessage, plain old objects can be used
  • Removed all threading from the endpoint (asynchronous message dispatching is now handled by a thread manager in the service bus
  • Added a DispatchMode so that messages could be dispatched synchronously for unit tests

I also wrote a new sample called HeavyLoad to benchmark the performance of the bus when using various transports. A variety of message per second tests are performed to see how well the system can be expected to perform based on the type of messaging being done. Early tests on my system (Windows 2003 server in VMware Fusion) show MSMQ performance to be between 950-1500 messages per second (for a 300 byte message, persistent) and around 500 messages per second doing a correlated request/response with a single thread (but using the asynchronous dispatcher). If I were to rewrite the test to use multiple message send threads I would expect performance to increase somewhat since my load test is a bit naive at the present time.

At the same time, I managed to extend the subscription support to include correlated subscriptions. The only subscription cache that currently supports the extensions is the DistributedSubscriptionCache (which uses memcached to share subscription information across a distributed group of systems). The key goal here was to enable MassTransit to support a distributed request/reply architecture using publish/subscribe with correlated subscriptions to specifically route messages to their intended consumers. I plan to make heavy use of this in an upcoming project so I wanted to see it work.

In addition to all the changes, I also updated a few of the samples and made various tweaks to the infrastructure to make it cleaner. There are several more tweaks on the whiteboard that I’m hoping to investigate in the next week. Once those are done, full ActiveMQ support is up next including running the tests under Mono on OSX.

So a lot of changes since the 0.1 tag was put down a couple of weeks ago. I expect there will be some continued testing and tweaking this week as Dru seeks to understand all the changes that were made. While I’ve been doing this stuff, Dru has gotten a kick ass start on a new dashboard to monitor an application built using MassTransit. The goal there is to provide a single pane of glass view into the health of a system, including subscriptions, endpoint throughput, message counts, etc. We’ve got some cool ideas how to make the information available and hope to make this alone one of the cool features to help support distributed messaging applications.

If you haven’t checked out MassTransit, you can get the latest source from the GoogleCode repository. There is a message board for questions, or feel free to contact Dru or myself with any questions.

May 06

It looks like VMware has dropped a public beta of VMware Fusion 2.0 to the public. There are too many new features in this release to mention, so I will just share the link:

http://communities.vmware.com/community/beta/fusion

Be sure to check the release notes to see if they impact your work before upgrading to this beta release.

Items of interest I took away from the release notes:

  • Use Fn+M to simulate the non-existent insert key in Windows (hello R#)
  • Multiple display support for virtual machines (hello second monitor)
  • Improved compatibility with Visual Studio (not sure what this is yet)

Be sure to check it out!

Apr 13

While the MVPs descend upon Seattle for the 2008 MVP Summit, I’m getting ready to head to Seattle for the ALT.NET Open Spaces Conference this coming weekend. Many of the people attending the ALT.NET conference are also MVPs, so there are likely to be some tired folks by the end of this week(end).

Based on the experience I had in Austin at the first ALT.NET conference, my company has agreed to send me to Seattle along with a couple of coworkers. A fellow developer and our agile project manager are going along to share in the experience and join the conversation. As an organization, we’ve seen many improvements since converting to agile development (XP-style) and I’m hoping the conference will help identify some new ways to help us grow and educate the rest of the team.

From a project perspective, Dru Sellers and I are trying to wrap up a 0.1 release of MassTransit in time for the event. We’re hoping to be able to share some of what we’ve done with others who are approaching a distributed application architecture, and even more importantly learn from others with similar experience so that we can improve MassTransit and add some new routing and management features. We’re getting there a couple of days early to have some time to pair up and knock out a few last minute tweaks before calling it good.

I’m looking forward to seeing a lot of the friends I met at the first event, as well as making some new friends. I’m excited to have “Doc” facilitating the event, his coordination of the first event was an inspiration at the start of each gathering (regardless of how many beers were consumed the night before).

As the event unfolds, I’ll be adding pictures to a web gallery for the event. Be sure to check it out (or add a subscription to the feed) if you weren’t able to attend in person. I’m sure there will be plenty of tweets as well, along with an RSS feed overload after every gathering.