Hi Nazariy,

I was able to remove the default ErrorAction and replace it with my own 
without changing the RSB code base.  I'll show you the code below, but 
first a caveat:  this code is for RSB 1.9.  I know there has been a lot of 
work done since then on containers, etc, so some of this may not work 
exactly the same way depending on what version you are using.

First, I had to create a new DefaultHost so I can change the way the 
container gets configured.  The methods in the DefaultHost are private, so 
I just copied the DefaultHost code into a new class.  When you start up 
RSB, you now have specify this new class as the host: 
 /Host:"MagicBus.Utils.RhinoServiceBus.MyDefaultHost,MagicBus.Utils".  The 
only code that needs to change in the class is in the InitializeContainer() 
method:  

private void InitializeContainer() 
 {

bootStrapper.InitializeContainer(container); 


if (hostConfiguration != null) 

container.Kernel.ConfigurationStore.AddFacilityConfiguration("rhino.esb", 
hostConfiguration); 


// This is the only line which is different than the DefaultHost that comes 
with RSB.

var facility = new MyServiceBusFacility(); 


bootStrapper.ConfigureBusFacility(facility); 

container.Kernel.AddFacility("rhino.esb", facility); 

} 


MyDefaultHost will now be configured with MyServiceBusFacility instead of 
the default implementation.   MyServiceBusFacility inherits from 
RhinoSerivceBusFacility to modify some configuration to include your custom 
ErrorAction.  First, I copied the Init method (actually from the 
AbstractRhinoServiceBusFacility) and change the line:


Kernel.Register( 
AllTypes.FromAssembly(typeof(IBusConfigurationAware).Assembly) 
.BasedOn<IBusConfigurationAware>() 
); 


To:


// Register our custom MsmqTransport configuration and exclude the
// version provided by RSB
Kernel.Register(
Component.For<IBusConfigurationAware>().ImplementedBy<MyMsmqTransportConfigurationAware>(),
AllTypes.FromAssembly(typeof (IBusConfigurationAware).Assembly)
.BasedOn<IBusConfigurationAware>()
.Unless(x => x == typeof (MsmqTransportConfigurationAware)));

You will have to override ReadConfiguration() as well.  Be sure to call 
base.ReadConfiguration first, then add any additional logic to Register the 
configuration information in the Kernel:


 /*  Do stuff to set up your configuration here */

// Register the custom error action here so it will be 
// first in the registrations and therefore the first 
// to receive the events we care about later 
Kernel.Register( 
Component.For<IMsmqTransportAction>() 
.ImplementedBy<ErrorHandlingAction>() 
.DependsOn(new 
{ 
numberOfRetries = NumberOfRetries, 
messageOwners, 
BusEndpoint = Endpoint.OriginalString 
})); 


 The code above will register ErrorHandlingAction to handle errors in place 
of the default Action in RSB.  My custom error handling will send an email 
to alert that an error has occurred. 
I went farther with my changes to configure the MSMQTransport to handle 
retries based on configuration values.  I had to make the following changes 
so that I could override the default behavior of using the numberOfRetries 
from the bus configuration.  You may or may not need to do this, depending 
on what you are trying to accomplish.

I created MyMsmqTransportConfigurationAware by copying 
the MsmqTransportConfigurationAware class and changing this:

Component.For<ITransport>()
.LifeStyle.Is(LifestyleType.Singleton)
.ImplementedBy(typeof(MsmqTransport))
.DependsOn(new
{
threadCount = facility.ThreadCount,
endpoint = facility.Endpoint,
queueIsolationLevel = facility.IsolationLevel,
numberOfRetries = facility.NumberOfRetries,
transactional = facility.Transactional,
consumeInTransaction = facility.ConsumeInTransaction,
}),

To:

Component.For<ITransport>()
.LifeStyle.Is(LifestyleType.Singleton)
.ImplementedBy(typeof(MyMsmqTransport))
.DependsOn(new
{
threadCount = facility.ThreadCount,
endpoint = facility.Endpoint,
queueIsolationLevel = facility.IsolationLevel,
numberOfRetries = facility.NumberOfRetries,
transactional = facility.Transactional,
consumeInTransaction = facility.ConsumeInTransaction,
}),


MyMsmqTransport is what determines what to do with an errored message: 
retry or move to the Errors queue.  I'm only using MSMQ for transport, so I 
ignored other transports for my case.

In the finally{} block of the ProcessMessage method I made changes to 
determine how often to retry the error, and how long the delay should be 
before retrying the message.

It took me a while to get this all working right.  I learned a lot about 
RSB, and Castle configuration along the way.  I had to copy code and create 
my own classes in places where the original code didn't allow access to its 
methods to inherit from the class, or override the methods.  I suspect 
there are more elegant ways to accomplish some of what I did using better 
configuration of the container, or something similar.  I would be happy to 
see improvements in this.  

I hope it helps.  I'm happy to provide more detail if you need it.

-Scott



On Friday, October 12, 2012 2:14:22 AM UTC-6, Nazariy Kotylo wrote:
>
> Hi Scott
>
> Do you know if it is possible to replace the ErrorAction with a custom one 
> without modifying the RhinoServiceBus source code?
>
> Пʼятниця, 24 серпня 2012 р. 19:18:53 UTC+3 користувач Scott написав:
>>
>> You can extend the service bus to add other behaviors to do what you 
>> want.  I don't have the code in front of me now, so I don't remember the 
>> exact implementation.  You can create your own flavor of the ErrorAction 
>> and modify the service bus or facility to load your Action instead of, or 
>> in addition to, the ErrorAction.  
>>
>> I did something similar in that the retries still occur, but the retry 
>> intervals are configurable and can be read from the config file at startup. 
>>  We have a specific case where this was necessary due to outages from an 
>> external service. The Action will also email the IT staff when the service 
>> bus hits its maximum number of retries and moves the message to the error 
>> queue.  
>>
>> It can be a little challenging to trace through the code to see where 
>>  and when Actions and MessageModules get loaded.  If you invest the time to 
>> understand the flow of the application on startup, you will discover how to 
>> plug in your custom code with very little effort.  
>>
>> -Scott
>>
>> On Wednesday, August 22, 2012 7:02:28 AM UTC-6, René M. Andersen wrote:
>>>
>>> Hi,
>>>
>>> Is it possible to configure the error handling behaviour when message 
>>> processing fails? I am specifically thinking about how to replace the 
>>> built-in ErrorAction which controls the retries and moves the message to 
>>> the error queue when all retries have been used.
>>>
>>> We would like to preserve the retry functionality but remove the message 
>>> from the queue instead of moving it to the error queue.
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Rhino Tools Dev" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/rhino-tools-dev/-/PWtgpYa1YkUJ.
To post to this group, send email to rhino-tools-dev@googlegroups.com.
To unsubscribe from this group, send email to 
rhino-tools-dev+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/rhino-tools-dev?hl=en.

Reply via email to