Nsb for certain type of exceptions: skip SLR + ability to ignore error queue - nservicebus

I want to have a central place to implement exceptions handling logic for specific type of exception.
If specific exception type occurs, I'd like to be able to run one of the following depending on internal configuration:
send message to error queue immediately without further second level retries;
hide the message, not sending it to both processing queue or error queue;
I've found this topic which covers first case but not second one, as a message would be put into error queue if we return TimeSpan.MinValue:
NServiceBus error handling
So how could I implement 2nd case? better both to be be implemented in one place, one class

Prior to version 6 of NServiceBus, you could use IManageMessageFailures to manage message failures. You can handle the case of a serialization exception or - more relevant to your problem at hand - when a message can not be handled gracefully after first-level retries are attempted.
Here's how to implement a custom FaultManager that'd ignore exceptions of certain type or send failed messages with other errors back to the error queue. Note that the First-Level retires still happens and this kicks-in instead of Second-Level retry.
public class IssueOrder : ICommand
{
public bool NotFound { get; set; }
public bool HasFaulted { get; set; }
}
public class OrderHandler : IHandleMessages<IssueOrder>
{
public void Handle(IssueOrder message)
{
if(message.NotFound)
throw new OrderNotFoundException();
if(message.HasFaulted)
throw new ApplicationException();
}
}
public class OrderNotFoundException : Exception
{
}
public class CustomFaultManager : IManageMessageFailures
{
private ISendMessages sender;
private MessageForwardingInCaseOfFaultConfig config;
private BusNotifications notifications;
private static ILog Logger = LogManager.GetLogger<CustomFaultManager>();
public CustomFaultManager(ISendMessages sender, IProvideConfiguration<MessageForwardingInCaseOfFaultConfig> config)
{
this.sender = sender;
this.config = config.GetConfiguration();
}
public void SerializationFailedForMessage(TransportMessage message, Exception e)
{
}
public void ProcessingAlwaysFailsForMessage(TransportMessage message, Exception e)
{
if (e is OrderNotFoundException)
{
//Ignore the exception;
Logger.WarnFormat("OrderNotFoundException was thrown. Ignoring the message Id {0}.", message.Id);
}
else
{
//Check if you have performed enough retries, ultimately send to error queue
SendToErrorQueue(message, e);
}
}
private void SendToErrorQueue(TransportMessage message, Exception ex)
{
message.TimeToBeReceived = TimeSpan.MaxValue;
sender.Send(message, new SendOptions(config.ErrorQueue));
Logger.WarnFormat("Message {0} will was moved to the error queue.", message.Id);
}
public void Init(Address address)
{
}
}
And to register the custom FaultManager:
var config = new BusConfiguration();
//Other configuration code
config.RegisterComponents(c =>
{
c.ConfigureComponent<CustomFaultManager>(DependencyLifecycle.InstancePerCall);
});
In Version 6 of NServiceBus however, the IManageMessageFailures interface is deprecated. The new Recoverability api in version 6 allows for better customization, althrough there's no direct way of ignoring/muting an exception. For that purpose you need a custom behavior in the NServiceBUs pipeline and run it in a step between one of the known steps (e.g. before a message is moved to the error queue).

Related

Can SagaData be manipulated before the saga handler fires using NServiceBus

Using NServiceBus (v6), is there a way to ensure that a property is set in the SagaData object before the Saga Handler for a message is fired?
Our environment is multi-tenant so I want to ensure that the correct CustomerId is used for db access etc.. and that developers don't forget to pull this value from the incoming message/message header.
For example given this saga data ...
public interface ICustomerSagaData : IContainSagaData
{
Guid CustomerId { get; set; }
}
public class SomeProcessSagaData : ICustomerSagaData
{
// IContainSagaData and other properties removed for brevity ...
#region ICustomerSagaData properties
public virtual Guid CustomerId { get; set; }
#endregion
}
... and the following Saga ...
public class SomeProcessSagaSaga :
Saga<SomeProcessSagaData>,
IAmStartedByMessages<StartProcess>
{
public async Task Handle(StartProcess message, IMessageHandlerContext context)
{
// How do I ensure that Data.CustomerId is already set at this point?
}
// ConfigureHowToFindSaga etc ...
}
I initially tried inserting a behaviour into the pipeline e.g.
public class MyInvokeHandlerBehavior : Behavior<IInvokeHandlerContext>
{
public override async Task Invoke(IInvokeHandlerContext context, Func<Task> next)
{
// Ideally I'd like to set the CustomerId here before the
// Saga Handler is invoked but calls to ...
// context.Extensions.TryGet(out activeSagaInstance);
// return a null activeSagaInstance
await next().ConfigureAwait(false);
// This is the only point I can get the saga data object but
// as mentioned above the hander has already been invoked
ActiveSagaInstance activeSagaInstance;
if (context.Extensions.TryGet(out activeSagaInstance))
{
var instance = activeSagaInstance.Instance.Entity as ICustomerSagaData;
if (instance != null)
{
Guid customerId;
if (Guid.TryParse(context.Headers["CustomerId"), out customerId))
{
instance.CustomerId = customerId;
}
}
}
}
}
... but this only allows access to the SagaData instance after the handler has been fired.
Late answer, but you need to make sure your behaviour executes after the SagaPersistenceBehavior.
In your IConfigureThisEndpoint implementation:
public virtual void Customize(EndpointConfiguration configuration)
{
configuration.Pipeline.Register<Registration>();
}
public class Registration : RegisterStep
{
public Registration()
: base(
stepId: "AuditMutator",
behavior: typeof(AuditMutator),
description: "Sets up for auditing")
{
this.InsertAfterIfExists("InvokeSaga");
}
}
So to answer your question directly Data.CustomerId is not going to be set when you handle StartProcess messages. You will need to set that with the id coming off of the message.
public async Task Handle(StartProcess message, IMessageHandlerContext context)
{
Data.CustomerId = message.CustomerId;
}
That being said your sample above is missing a crucial piece which is the code for determining how a saga can be looked up for continuation of processing:
protected override void ConfigureHowToFindSaga(SagaPropertyMapper<SomeProcessSagaData> mapper)
{
mapper.ConfigureMapping<StartProcess>(message => message.CustomerId)
.ToSaga(sagaData => sagaData.CustomerId);
}
Each time you send a message type that is handled by a saga you need to have the ConfigureHowToFindSaga() method configured so it can look up the previously started saga to continue processing with. So in essence you are going to start a new saga for every customerid you send with a StartProcess message. You can read more about it here: https://docs.particular.net/nservicebus/sagas/
So the real question now is do you really need to be using a saga at this point? The sample only seems to be handling one type of message so do you really need to be saving the state of CustomerId? The overhead of the saga isn't necessary in your sample and I believe a regular handler would be just fine based on the example above.

Is there some way to keep domain events context unaware with NServiceBus 6 and the removal of IBus?

I'm wrestling with a situation where we currently use the IBus interface (NServiceBus v5) in domain event handlers to send commands to a backend service for processing. With the IBus, these commands could be sent regardless of what triggered the event, whether while receiving a Web API request or as part of an NServiceBus handler (common domain model). But, in NServiceBus v6, with the shift to context specific interfaces, IEndpointInstance or IMessageHandlerContext, it seems that my domain event handlers now need to become context aware. And further, it looks like the IMessageHandlerContext is only available via method injection, so I may have to sprinkle this parameter all throughout the call stack?
Is there some approach that I'm not seeing whereby I can keep my domain event handlers context unaware? Or have I followed some bad practice that's revealing itself through this code smell?
EDIT
Here's an attempt at boiling down the scenario to the most relevant pieces. There's an order in the domain model whose status may change. When the status of the order changes, we've been firing off a StatusChanged domain event through a publisher. A subscriber to this particular domain event writes out a record of the status change and also sends out an NServiceBus command to communicate this status out - the handler for this particular command will follow some further logic on whether to send out emails, SMS messages, etc., the details of which I don't think are relevant.
Order Domain Object
public class Order
{
private OrderStatusCode _statusCode;
public OrderStatusCode StatusCode
{
get { return _statusCode; }
private set { _statusCode = value; }
}
public void ChangeStatus(OrderStatusCode status)
{
Status = status;
Publish(new StatusChanged(CreateOrderSnapshot(), status));
}
protected void Publish<T>(T #event) where T : IDomainEvent
{
DomainEventPublisher.Instance.Publish(#event);
}
}
Domain Event Publisher
public class DomainEventPublisher : IDomainEventPublisher
{
private static IDomainEventPublisher _instance;
public static IDomainEventPublisher Instance
{
get { return _instance ?? (_instance = new DomainEventPublisher()); }
}
public ISubscriptionService SubscriptionService { get; set; }
public void Publish<T>(T #event) where T : IDomainEvent
{
if (SubscriptionService == null) return;
var subscriptions = SubscriptionService.GetSubscriptions<T>();
subscriptions.ToList().ForEach(x => PublishToConsumer(x, #event).GetAwaiter().GetResult());
}
private static async Task PublishToConsumer<T>(IEventSubscriber<T> x, T eventMessage) where T : IDomainEvent
{
await x.HandleEvent(eventMessage);
}
}
Status Changed Domain Event Handler
public class StatusChangedHandler : IEventSubscriber<StatusChanged>
{
private readonly IBus _bus;
private readonly IOrdersRepository _ordersRepository;
public StatusChangedHandler(IBus bus, IOrdersRepository ordersRepository)
{
_bus = bus;
_ordersRepository = ordersRepository;
}
public async Task HandleEvent(StatusChanged #event)
{
var statusTrailEntry = new OrderStatusTrailEntry(#event.OrderSnapshot, #event.Status);
var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
using (
var scope = new TransactionScope(TransactionScopeOption.Required, txOptions))
{
await _ordersRepository.SaveStatusTrail(statusTrailEntry);
if (communicateStatus)
{
_bus.Send(new SendCommunicationCommand(#event.OrderSnapshot, #event.Status));
}
scope.Complete();
}
}
}
The things is, up until now none of the sample code above has needed to know whether the status changed as a result of a request coming in through a Web API request or as a result of a status being changed within the context of an NServiceBus message handler (within a windows service) - the IBus interface is not context specific. But with the differentiation between IEndpointInstance and IMessageHandlerContext in NServiceBus v6, I don't feel that I have the same flexibility.
If I understand correctly, I'm able to register the IEndpointInstance with my container and inject into the EventSubscriber, so I'd be covered in the case of a Web API call, but I'd also need to add an IMessageHandlerContext as a parameter to optionally be passed down through the call stack from ChangeStatus to the Publisher and finally to the Domain Event Subscriber if the status happens to be changed within the context of a message handler. Really doesn't feel right to be adding this parameter all throughout the call stack.

WCF oneway exception faults channel

I haven't found a clear answer on this. so if there is already a question about this, my bad.
I have a WCF service that pushes data via a callback method to connected clients. this callback method is oneway. so everytime there is new data I loop over the connected users and push the data.
The problem I have right now is when a client disconnects it throws an error and the channel becomes faulted.
I always thought that oneway didn't care if the message arrives at the destination. So if there's no client, then bad luck. but no exception.
but there is an exception and that exception faults the channel.
Now I've read somewhere that if you enable reliable sessions, that the exception won't fault the channel. Is this true?
How can I prevent that the channel goes into faulted state when an exception happens on a oneway call?
The list of registered and avaiable clients you can store in some resource such as List. Create another interface which exposes Connect/Disconnect methods. Connect is invoked when application starts off and within method client is added to the list. Disconnect in turn is invoked when application shuts down in order to get rid client of list. OnStartup/OnClosing events or their equivalents, depending on what kind of application client is, refer to moment when application is launched and closed. Such a solution ensures that resource stores only users avaiable to be reached.
[ServiceContract]
interface IConnection
{
[OperationContract(IsOneWay = true)]
void Connect();
[OperationContract(IsOneWay = true)]
void Disconnect();
}
[ServiceContract]
interface IServiceCallback
{
[OperationContract(IsOneWay = true)]
void CallbackMethod();
}
[ServiceContract(CallbackContract = typeof(IServiceCallback))]
interface IService
{
[OperationContract]
void DoSth();
}
class YourService : IConnection, IService
{
private static readonly List<IServiceCallback> Clients = new List<IServiceCallback>();
public void Connect()
{
var newClient = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
if (Clients.All(client => client != newClient))
Clients.Add(newClient);
}
public void Disconnect()
{
var client = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
if (Clients.Any(cl => cl == client))
Clients.Remove(client);
}
public void DoSth()
{
foreach(var client in Clients)
client.CallbackMethod();
}
}
At the end expose another endpoint with IConnection so that client can create proxy meant to be used only for connection/disconnection.
EDIT:
I know it has been a while since I posted an answear but I did not find in order to prepare an example. The workaround is to let service's interface derive IConnection and then expose only service as an endpoint. I attach simple example of WCF and WPF app as client. Client's application violates MVVM pattern but in this case it is irrelevant. Download it here.
To add on what Maximus said.
I've implemented this pattern in a class where clients can subscribe to get updates of internal states of a system, so a monitoring client can show graphs and other clients do other stuff like enabling/disabling buttons if some state is active.
It removes faulted channels from the list when they fail. Also all current states are sent when a client connects.
here's the code, hope it helps!
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Publish : IPublish
{
private struct SystemState
{
public string State;
public string ExtraInfo;
}
private static Dictionary<Key<string>, IPublishCallback> mCallbacks = new Dictionary<Key<string>, IPublishCallback>();
private static Dictionary<string, SystemState> mStates = new Dictionary<string, SystemState>();
public void RegisterClient(string name, string system)
{
lock (mCallbacks)
{
IPublishCallback callback = OperationContext.Current.GetCallbackChannel<IPublishCallback>();
Key<string> key = new Key<string>(name, system);
if (!mCallbacks.ContainsKey(key))
{
mCallbacks.Add(key, callback);
}
else
{
mCallbacks[key] = callback;
}
foreach (KeyValuePair<string, SystemState> s in mStates)
{
mCallbacks[key].ServiceCallback(s.Key, s.Value.State, s.Value.ExtraInfo);
}
}
}
public void UnregisterClient(string name)
{
lock (mCallbacks)
{
outer: foreach (var key in mCallbacks.Keys)
{
if (key.Key1 == name)
{
mCallbacks.Remove(key);
goto outer;
}
}
}
}
public void SetState(string system, string state, string extraInfo)
{
lock (mCallbacks)
{
List<Key<string>> toRemove = new List<Key<string>>();
SystemState s = new SystemState() { State = state, ExtraInfo = extraInfo };
SystemState systemState;
if (!mStates.TryGetValue(system, out systemState))
mStates.Add(system, s);
else
mStates[system] = s;
foreach (KeyValuePair<Key<string>, IPublishCallback> callback in mCallbacks)
{
try
{
callback.Value.ServiceCallback(system, state, extraInfo);
}
catch (CommunicationException ex)
{
toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
}
catch
{
toRemove.Add(new Key<string>(callback.Key.Key1, callback.Key.Key2));
}
}
foreach (Key<string> key in toRemove)
mCallbacks.Remove(key);
}
}
}

WCF: ServiceClient + Dispose

This is what I understand from why we need to implement our own wrapper class for serviceClients (please correct me if I'm wrong):
The purpose of catching the exception
in the Dispose() method is that
.Close() may throw either a
"CommunicationException" or
"TimeoutException" - and to prevent
the connection to hang you catch those
two exceptions to use .Abort() which
will change the state of the
communication object to closed
immediatley. - it would not make any
sense to let the exception be
unhandled because the nessecary calls
to the methods have already been made
since we're at the Dispose() part, and
it would therefore be odd to throw an
exception when the job actually is
done as it should.
But why do:
public class ServiceClientWrapper<TServiceType> : IDisposable
{
public TServiceType Channel { get; private set; }
private readonly ChannelFactory<TServiceType> _channelFactory;
public ServiceClientWrapper(string endpoint)
{
_channelFactory = new ChannelFactory<TServiceType>(endpoint);
Channel = _channelFactory.CreateChannel();
((IChannel)Channel).Open();
}
#region Implementation of IDisposable
public void Dispose()
{
try
{
((IChannel)Channel).Close();
}
catch (CommunicationException ex)
{
((IChannel)Channel).Abort();
}
catch (TimeoutException ex)
{
((IChannel)Channel).Abort();
}
catch (Exception)
{
((IChannel)Channel).Abort();
throw;
}
}
#endregion
}
When you can do:
public class ServiceClientWrapper<TServiceType> : IDisposable
{
public TServiceType Channel { get; private set; }
private readonly ChannelFactory<TServiceType> _channelFactory;
public ServiceClientWrapper(string endpoint)
{
_channelFactory = new ChannelFactory<TServiceType>(endpoint);
Channel = _channelFactory.CreateChannel();
((IChannel)Channel).Open();
}
#region Implementation of IDisposable
public void Dispose()
{
((IChannel)Channel).Abort();
}
#endregion
}
According to MSDN both .Close() and .Abort() will change the state of the communication object to "Closed"?
The point is that Close() will aim to close the entire communication channel gracefully, including any closing handshake required by the communication protocol, whereas Abort() is a rude and brutal tearing down of the client-side channel stack with no attempt to communicate the closure properly to the other side. Abort may therefore leave server-side resources still tied up on a connections which will not be used further.
So we always want to execute Close if possible, but we need to handle situations where things are so broken that trying to do a Close will cause a further exception.
Close method:
http://msdn.microsoft.com/en-us/library/ms405496.aspx
This method causes a CommunicationObject to gracefully transition from any state, other than the Closed state, into the Closed state. The Close method allows any unfinished work to be completed before returning. For example, finish sending any buffered messages.
Abort method
Does the same ungracefully or as stated in the specs immediately. It will NOT finish anything still going on...

Did i understood MsmqPoisonMessageException wrong?

If i got a service definition like this:
[PoisonErrorBehavior]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MsgQueue: IMsgQueue
{
public void ProcessMsg(CustomMsg msg)
{
throw new Exception("Test");
}
}
( where ProcessMsg is the registered method for incoming msmq-messages )
and i want to handle the exception with my error handler ( i took the code from msdn as a template for mine ):
public sealed class PoisonErrorBehaviorAttribute : Attribute, IServiceBehavior
{
MsmqPoisonMessageHandler poisonErrorHandler;
public PoisonErrorBehaviorAttribute()
{
this.poisonErrorHandler = new MsmqPoisonMessageHandler();
}
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
{
}
void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(poisonErrorHandler);
}
}
}
class MsmqPoisonMessageHandler : IErrorHandler
{
public void ProvideFault(Exception error, MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
}
public bool HandleError(Exception error)
{
string test = error.GetType().ToString();
//
// The type of the exception is never MsmqPoisonMessageException !!!
//
MsmqPoisonMessageException poisonException = error as MsmqPoisonMessageException;
if (null != poisonException)
{
long lookupId = poisonException.MessageLookupId;
Console.WriteLine(" Poisoned message -message look up id = {0}", lookupId);
}
}
then i got the problem that the exception is never of type MsmqPoisonMessageException. I would have expected .NET to magically encapsulate my "new Exception("Test")" in a MsmqPoisonMessageException, but the exception catched in my errorhandler is always of the same type as the exception i threw.
Am i missunderstanding this whole poison message behavior? I thought if an unhandled exception was thrown by my message-handling-code then the exception would turn out to be a MsmqPoisonMessageException, because otherwise i would'nt have a chance to get the lookup-id of msg in the queue.
Thank you all.
WCF encapsulates exceptions in a fault exception.
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultexception.aspx
You must also specify which exceptions are to be thrown in the Interface / Contract.
First of all, you need to be retrieving the messages inside of a transaction, otherwise they won't be put back to the queue when there is an exception thrown from your code. Add this to the ProcessMessage function:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
Also, you need to make sure that binding is set to fault when poison messages are detected, and that the retry count and time are small enough that you'll see it in your testing.
Try these steps (using VS 2008):
Open the WCF Configuration tool for your app.config file
Select Bindings in the tree, and click "New Binding Configuration" in the tasks area
Select the binding type of your endpoint (probably netMsmqBinding or msmqIntegrationBinding)
Set the name of the new binding configuration
Set the ReceiveErrorHandling property to "Fault"
Set the ReceiveRetryCount property to 2
Set the RetryCycleDelay to "00:00:10"
Select the endpoint to your service and set the binding configuration to the name you specified in step 4.
(You will probably want different values for ReceiveRetryCount and RetryCycleDelay for your production configuration.)