Search code examples
azureazureservicebusmasstransitstate-machinesaga

.NET - MassTransit - StateMachine fault message for all


I have a question about statmachine in the masstransit library. This is my code:

public Event<Requested>? Requested { get; }
public Event<Started>? Started { get; }
public Event<ArchiveFinished>? ArchiveFinished { get; }
public Event? Finished { get; }

public Test() {
            InstanceState(x => x.CurrentState);

            Event(() => Requested, x => x.CorrelateById(context => context.Message.RequestId));

            Event(() => Started, x => x.CorrelateById(context => context.Message.RequestId));

            Event(() => ArchiveFinished, x => x.CorrelateById(context => context.Message.RequestId));

            Initially(
                 When(Requested),
                 When(Started),
                 When(ArchiveFinished)
            );

            CompositeEvent(() => Finished,
                x => x.ReadyEventStatus,
                CompositeEventOptions.IncludeInitial,
                Requested,
                Started,
                ArchiveFinished
            );

            DuringAny(
                When(Finished)
                .Publish(context => new Finished() { RequestId = RequestId })
                .Finalize()
            );

            // Error in any of events?

            SetCompletedWhenFinalized();
}

The thing is that the state machine works exactly as I have. But one thing is not working at all. If there is an error in any of the events, I can see that there is a fault message for that message. But I would need, when an error occurs in any of the given events to call somehow a fault message. Is this somehow possible? I tried Catch it didn't work. Finished fault does not work.

Edit:

For example, if a Requested message is being processed and an error occurs in a given consumer, a new Requested-Fault message will be created. There everything necessary can be processed. However, I would still need some way to react to this situation in the state machine. Create a message something like FinishedFault. And I would need this in case an error/exception occurs in any consumer for the Requested, Started or ArchiveFinished message. Hopefully it's clearer this way.

Edit 2

public Event<Requested>? Requested { get; }
public Event<Fault<Requested>>? RequestedFault { get; }
public Event<Started>? Started { get; }
public Event<Fault<Started>>? StartedFault { get; }
public Event<ArchiveFinished>? ArchiveFinished { get; }
public Event<Fault<ArchiveFinished>>? ArchiveFinishedFault { get; }
public Event? Finished { get; }

public Test() {
            InstanceState(x => x.CurrentState);

            Event(() => Requested, x => x.CorrelateById(context => context.Message.RequestId));
            Event(() => RequestedFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
            Event(() => Started, x => x.CorrelateById(context => context.Message.RequestId));
            Event(() => StartedFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
            Event(() => ArchiveFinished, x => x.CorrelateById(context => context.Message.RequestId));
            Event(() => ArchiveFinishedFault, x => x.CorrelateById(context => context.Message.Message.RequestId));

            Initially(
                 When(Requested),
                 When(RequestedFault)
                    .Publish(context => new FinishedFault...),
                 When(Started),                 
                 When(StartedFault),                 
                    .Publish(context => new FinishedFault...),
                 When(ArchiveFinished),
                 When(ArchiveFinishedFault),
                    .Publish(context => new FinishedFault...)
            );

            CompositeEvent(() => Finished,
                x => x.ReadyEventStatus,
                CompositeEventOptions.IncludeInitial,
                Requested,
                Started,
                ArchiveFinished
            );

            DuringAny(
                When(Finished)
                .Publish(context => new Finished() { RequestId = RequestId })
                .Finalize()
            );

            // Error in any of events?

            SetCompletedWhenFinalized();
}

Solution

  • You can consume faults in a state machine using:

    Event<Fault<T>>
    

    Where T is the original message type.