When implementing a global handler for IHandleSagaNotFound, is it possible to obtain information on which saga was tried to load?
I have a design where one published message would have to resurrect 2 sagas.
If a saga cannot be found for a reason, I would throw an exception, so the message is retried and eventually sent to the error queue.
In the other case, I would not throw an exception and just “ignore” the message.
One solution could be to redesign those 2 sagas into one.
But that would be my last option.
I was thinking of implementing a behavior that hooks in before the SagaPersistenceBehavior, to store the saga information somewhere, and use that in the SagaNotFoundHandler.
Anyone already implemented such a behavior?
Some pointers are most welcome.
Hi Steven, you can get access to the list of saga involved by extending the receive pipeline. ( I’ve cobbled together some code that will get you going)
Add the following 2 behaviors
class SagaTypeRecorder : Behavior<IInvokeHandlerContext>
{
public override Task Invoke(IInvokeHandlerContext context, Func<Task> next)
{
if(context.MessageHandler.Instance is Saga)
{
var sagas = context.Extensions.Get<SagaTypeHolder.SagasInvolved>();
sagas.Sagas.Add(context.MessageHandler.HandlerType);
}
return next();
}
}
class SagaTypeHolder : Behavior<IIncomingPhysicalMessageContext>
{
public override Task Invoke(IIncomingPhysicalMessageContext context, Func<Task> next)
{
context.Extensions.Set(new SagasInvolved());
return next();
}
public class SagasInvolved
{
public List<Type> Sagas = new List<Type>();
}
}
and register them:
endpointConfiguration.Pipeline.Register(typeof(SagaTypeHolder), "Holds potential sagas for the incoming message");
endpointConfiguration.Pipeline.Register(typeof(SagaTypeRecorder), "Records potential sagas for the incoming message");
You can then use this in your saga not found handler
public Task Handle(object message, IMessageProcessingContext context)
{
var involvedSagas = context.Extensions.Get<SagaTypeHolder.SagasInvolved>();
foreach(var sagaType in involvedSagas.Sagas)
{
Console.Out.WriteLine(sagaType.FullName);
}
return Task.CompletedTask;
}
That said, your design sounds a bit funky so perhaps refactoring this into a single saga might be the better long term solution?