MassTransit Activity Fault with parameters

Viewed 1226

I am currently using Masstransit in with the Courier pattern.

I´ve set up an Activity which may fail, and I want to be able to subscribe to this failure and act accordingly.

My problem is, even though I can subscribe to the failure, and even see the exception that caused the failure, I am unable to pass any arguments to it.

For testing purposes, supose I have the following activity:

public class MyActivity : ExecuteActivity<MyMessage>
{
    public Task<ExecutionResult> Execute(ExecuteContext<MyMessage> context)
    {
        try
        {
           // .... some code
            throw new FaultException<RegistrationRefusedData>(
                new RegistrationRefusedData(RegistrationRefusedReason.ItemUnavailable));
            // .... some code
        }
        catch (Exception ex)
        {
            return Task.FromResult(context.Faulted(ex));
        }
    }
}

The problem is in the reason (RegistrationRefusedReason) I am passing as a argument of the exception. If I subscribe a RoutingSlipActivityFaulted consumer, I can almost get all the information I need:

public class ActivityFaultedConsumer : IMessageConsumer<RoutingSlipActivityFaulted>
{
    public void Consume(RoutingSlipActivityFaulted message)
    {
        string exceptionMessage = message.ExceptionInfo.Message; // OK
        string messageType = message.ExceptionInfo.ExceptionType; // OK
        RegistrationRefusedReason reason =  ??????;
    }
}

I feel like I am missing something important here, (maybe misusing the pattern?).

Is there any other way to get parameters from a faulted activity ?

2 Answers

Kinda raising this from the dead, but I really haven't found a neat solution to this.

Here is my scenario:

  1. I want to implement a request/response, but I want to wait for the execution of a routing slip.
  2. As Fabio, I want to compensate for any previous activities and I want to pass data back to the request client in case of a fault.

Conveniently, Chris provided a RoutingSlipRequestProxy/RoutingSlipResponseProxy which does just that. I've found 2 approaches, but both of them seem very hacky to me.

Approach 1:

  1. The request client waits for ISimpleResponse or ISimpleFailResponse.
  2. RoutingSlipRequestProxy sets the ResponseAddress in the variables.
  3. The activity sends ISimpleFailResponse to the ResponseAddress.
  4. The client waits for either response
  5. The RoutingSlipResponseProxy sends back Fault<ISimpleResponse> to the ResponseAddress.

From what I see the hackiness comes from step 4/5 and their order. I am pretty sure it works, but it could easily stop working in case messages are consumed out-of-order.

Sample code: https://github.com/steliyan/Sample-RequestResponse/commit/3fcb196804d9db48617a49c7a8f8c276b47b03ef

Approach 2:

  1. The request client waits for ISimpleResponse or ISimpleFailResponse.
  2. The activity calls ReviseItirery with the variables and adds a faulty activity.*
  3. The faulty activity faults
  4. The RoutingSlipResponseProxy2 get the ValidationErrors and sends back ISimpleFailResponse to the ResponseAddress.

* The activity needs to be Activity and not ExecuteActivity because there is no overload of ReviseItinerary with variables but with no activity log.

This approach seems hacky because an additional fault activity is added to the itinerary, just to be able to add a variable to the routing slip.

Sample code: https://github.com/steliyan/Sample-RequestResponse/commit/e9644fa683255f2bda8ae33d8add742f6ffe3817

Conclusion: Looking at MassTransit code, it doesn't seem like a problem to add a FaultedWithVariables overload. However, I think Chris' point is that there should be a better way to design the workflow, but I am not sure about that.

Related