ActiveMQ via C# Part 3: Simplifying the API using a Provider Pattern

by jmorris 24. September 2010 16:05

Background

In my previous posts I developed simple sender and receiver classes for topics and queues using Apache.NMS and ActiveMQ. In this post I will use the provider pattern to simplify creation and management of NMS connections, senders and receivers. Additionally, I’ll improve the syntax and ease of using NMS by adding fluent-interface behavior to the sender and receiver classes previously developed in part 1 and part 2, as well as a little refactoring to better manage the lifetime of the objects.

  1. http://rantdriven.com/post/ActiveMQ-via-C-sharp-and-dotnet-using-ApacheNMS-Part-1.aspx
  2. http://rantdriven.com/post/ActiveMQ-via-C-using-ApacheNMS-Part-2-Queues.aspx

Provider Pattern Background

The provider pattern is a software pattern developed at Microsoft during the development of ASP.NET 2.0 and used pretty extensively in that release. The most noticeable implementation was the Membership API, where the data storage of your security was abstracted away from the implementation. The aim is the pattern is loose coupling similar to what is provided by an IoC and DI, such as Ninject or Windsor container via settings in a configuration file as injected parameters.

There has been a bit of debate over whether or not it is a true pattern with most people agreeing that it’s a really several patterns or simply another pattern with a different name; most notable the Factory and Strategy patterns in some circles and the Singleton or Bridge patterns in others. The Bridge pattern definition most closely matches the goals of the pattern:

"decouple an abstraction from its implementation so that the two can vary independently"

- Gamma, Helm, Johnson, and Vlissides (gof)

As far as I am concerned it is a sort of hybrid pattern; a composition of patterns if you will.

Provider Pattern Implementation

The provider pattern itself is deeply ingrained within .NET itself; there is even a namespace with base classes supporting the pattern – System.Configuration.Provider. This namespace contains the following base classes, BaseProvider and ProviderCollection which are the building blocks of configuration based providers. System.Configuration adds another abstract class that makes working with .NET configuration files easier. Note that you could in theory create your own provider implementation without using these classes, but they provide an easy to follow framework for making providers using .NET.

The following diagram illustrates the entire provider implementation:

provider-api

Here is a rundown of the various classes required:

  • NmsProvider – derives from BaseProvider and provides initialization for the provider plus factory methods for creating NMS senders and receievers. Only one instance of a configuration should exist for an AppDomain or process and all operations should be thread safe.
  • NmsProviderCollection – derives from ProviderCollection and maintains a list of configured providers. For example you could have providers configured for multiple ActiveMQ servers i.e. receive from one server and send to another.
  • NmsProviderConfigurationSection – provides a defined section in your configuration file for each provider implementation.
  •  NmsProviderService – a singleton ‘service’ for maintaining the collection of providers while your application is running. Note that providers are long lived objects, hence the need for a singleton to maintain the list.

The NmsProvider class is really a façade encapsulating the interaction between the JMS broker and the client’s it services. From a client perspective it manages the connection between the client and the JMS broker, the sessions that are generated per conversation, as well as the creation of objects for sending JMS messages to receiving messages from destinations (queues and topics). An important point to remember is that JMS Connections are heavyweight, long lived objects and are typically created 1:1 with clients, which “fits” well with the lifecycle of providers.

All providers use configuration files to store the type of provider to initialize and any additionally information that must be injected into the newly created instance. Note that this is a form of Dependency Injection (DI). The configuration file may contain configurations for multiple instances of each provider configured differently. For example, each provider may be using a different broker to send or receive messages. Here is a listing of a configuration that lists several provider instances using the same broker:

 

When the NmsProviderService is created, it will read the contents of NmsProviderConfigurationSection and construct providers for each entry in the “providers” section; in this case two providers are listed: NmsProvider0 and NmsProvider1. The System.Configuration namespace contains a special class to help in creating the providers called ProvidersHelper. After the providers are created they are added to the NmsProviderCollection, which is a thread safe collection of providers.

When the provider is created by the ProvidersHelper.InstantiateProviders method in the NmsProviderService class, the overriden ProviderBase.Initialize method will be called in the NmsProvider class. The Initialize method will assign the values stored in the configuration file to their respective properties on the NmsProvider class and then create an instance of the Apache.NMS.ConnectionFactory class.

image

As previously discussed, the NmsProvider is façade encapsulating the interaction between the JMS server and the clients that it services. It is also a factory in that it offers methods for creating objects for sending and receiving messages. Notable it hold references to Apache.NMS.IConnection and Apache.NMS.IConnectionFactory objects. The IConnectionFactory class is a factory for creating IConnection instances based on the configuration supplied.

Clients use providers by name via and indexer on the NmsProviderService after calling the Start() method on the provider to create the connection between the client and the JMS server:

 image

 

The Start() method creates a new IConnection if the provider does not have one already initialized. Then it checks to see if the IConnection is started, if not then the IConnection’s Start() method is called which establishes the connection with the JMS server.  Additional methods on the provider allow the IConnection to be temporarily stopped or permanently closed:

image

Once the provider has been initialized, the usage is quite simple:

image

**Make sure you have ActiveMQ running and your configuration file is configured with the appropriate uri. See http://rantdriven.com/post/ActiveMQ-via-C-sharp-and-dotnet-using-ApacheNMS-Part-1.aspx for details on how to get ActiveMq up and running on a windows box.

References

 

 

Tags: , ,

Apache.NMS, JMS

OOM Exceptions Max Addressable Space and Apache.NMS

by jmorris 15. June 2010 17:30

I kept running into OutOfMemoryExceptions in one my Unit Tests that tested some very basic pub/sub functionality with Apache.NMS. Basically, I could create aproximently 1835 consumers before the following exception was thrown:

I was a bit perplexed by this exception, first all because it happened at nearly the exact same number of consumers being created. Secondly, because that really wasn't that high of a number...I was expected failures to be in 100K or even 1M range...

Looking at my code, the problem became clear as day: I was creating a session per consumer.

Why is this bad? Little background on JMS (Java Messaging Service), which of course Apache.NMS is based (dotnet for JMS):

  • Each client should have a single connection
  • Each connection should manage less than 500 sessions
  • Each session is a thread
  • Each session can create n consumers/subscribers

The problem I was having is that I was running out of addressable space when I was creating 1:1 session to consumer. Each thread took up approximently 1MB thread stack * ~2000 session objects => 2GB max addressable memory space on a windows x86 process. Given that I was running a unit test with Resharper in VS2008, which undoubtedly consumes more threads, I reached the threshold at slightly lower than 2K threads.

With a simple refactor, I was able to run a subsquent unit test where 100K consumers were created on a single session!

Tags: ,

Apache.NMS | JMS

Jeff Morris

Tag cloud

Month List

Page List