Hi I have a problem in state machine and I really don't know what to do anymore. The thing is that the state machine works as it should, but if an exception occurs in the consumer from the DataRunningFault message, it correctly switches the state to ClearDataState and waits to see if DataCalculated or DataReport is running (the error in the consumer can occur after the DataCalculated/DataReport message is sent). Thus, I wait to see if it runs and if it does, I delete the data. More or less it works, but I get this exception.
public class DataState : SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public int CurrentState { get; set; }
public int ReadyEventStatus { get; set; }
public Guid RequestId { get; set; }
}
public class DataStateMachine : MassTransitStateMachine<DataState>
{
public Event<DataRequested>? DatakRequested { get; }
public Event<Fault<DataRequested>>? DataRequestedFault { get; }
public Event<DataRunning>? DataRunning { get; }
public Event<Fault<DataRunning>>? DataRunningFault { get; }
public Event<DataCalculated> DataCalculated { get; }
public Event<Fault<DataCalculated>>? DataCalculatedFault { get; }
public Event<DataReport> DataReport { get; }
public Event<Fault<DataReport>>? DataReportFault { get; }
public MassTransit.Event? Finished { get; }
public State? ClearDataState { get; }
public DataStateMachine()
{
InstanceState(x => x.CurrentState);
Event(() => DataRequested, x => x.CorrelateById(context => context.Message.RequestId));
Event(() => DataRequestFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
Event(() => DataRunning, x => x.CorrelateById(context => context.Message.RequestId));
Event(() => DataRunningFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
Event(() => DataCalculated, x => x.CorrelateById(context => context.Message.RequestId));
Event(() => DataCalculatedFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
Event(() => DataReport, x => x.CorrelateById(context => context.Message.RequestId));
Event(() => DataReportFault, x => x.CorrelateById(context => context.Message.Message.RequestId));
Initially(
When(DataRequested)
.Then(x =>
{
x.Saga.Entities = x.Message.Entities;
x.Saga.BatchDate = x.Message.BatchDate;
x.Saga.RequestId = x.Message.RequestId;
}),
When(DataRequestFault)
.Publish(x => Fault(x.Saga))
.TransitionTo(ClearDataState),
When(DataRunning),
When(DataRunningFault)
.Publish(x => Fault(x.Saga))
.TransitionTo(ClearDataState),
When(DataCalculated),
When(DataCalculatedFault)
.Publish(x => Fault(x.Saga))
.Finalize(),
When(DataReport),
When(DataReportFault)
.Publish(x => Fault(x.Saga))
.Finalize()
);
During(ClearDataState,
When(DataCalculated)
.Publish(x => new DeleteCalculateData() { RequestId = x.Message.RequestId })
.Finalize(),
When(DataReport)
.Publish(x => new DeleteCalculateData() { RequestId = x.Message.RequestId })
.Finalize()
);
CompositeEvent(() => Finished,
x => x.ReadyEventStatus,
CompositeEventOptions.IncludeInitial,
DataRequested,
DataRunning,
DataCalculated
);
During(Initial,
When(Finished)
.Publish(context =>
{
return new DataFinished() { RequestId = context.Saga.RequestId };
})
.Finalize()
);
SetCompletedWhenFinalized();
}
private DataFinishedFault Fault(RunDataState runDataState)
{
return new DataFinishedFault() { RequestId = runDataState.RequestId };
}
}
Exception:
MassTransit: Error: R-FAULT sb://testbusfortestingstandard.servicebus.windows.net/messaging-run-data-state bca30000-4395-e04f-ceb8-08dbe1bde727 SharedContracts.Messages.ReportCalculateFinished Messaging.StateMachines.DataState(00:00:00.8759128)
MassTransit.NotAcceptedStateMachineException: Messaging.StateMachines.DataState(63331cb1-6165-4260-9577-66be080a3d9e) Saga exception on receipt of SharedContracts.Messages.DataReport: Not accepted in state Final
---> MassTransit.UnhandledEventException: The DataReport event is not handled during the Final state for the DataStateMachine state machine
at MassTransit.MassTransitStateMachine`1.DefaultUnhandledEventCallback(UnhandledEventContext`1 context) in /_/src/MassTransit/SagaStateMachine/MassTransitStateMachine.cs:line 219
at MassTransit.MassTransitStateMachine`1.UnhandledEvent(BehaviorContext`1 context, State state) in /_/src/MassTransit/SagaStateMachine/MassTransitStateMachine.cs:line 1260
at MassTransit.MassTransitStateMachine`1.<.ctor>b__13_2(BehaviorContext`1 context, State state) in /_/src/MassTransit/SagaStateMachine/MassTransitStateMachine.cs:line 52
at MassTransit.SagaStateMachine.StateMachineState`1.MassTransit.State<TSaga>.Raise[T](BehaviorContext`2 context) in /_/src/MassTransit/SagaStateMachine/SagaStateMachine/StateMachineState.cs:line 162
at MassTransit.MassTransitStateMachine`1.MassTransit.StateMachine<TInstance>.RaiseEvent[T](BehaviorContext`2 context) in /_/src/MassTransit/SagaStateMachine/MassTransitStateMachine.cs:line 132
at MassTransit.Middleware.StateMachineSagaMessageFilter`2.Send(SagaConsumeContext`2 context, IPipe`1 next) in /_/src/MassTransit/Middleware/StateMachineSagaMessageFilter.cs:line 66
--- End of inner exception stack trace ---
at MassTransit.Middleware.StateMachineSagaMessageFilter`2.Send(SagaConsumeContext`2 context, IPipe`1 next) in /_/src/MassTransit/Middleware/StateMachineSagaMessageFilter.cs:line 81
at MassTransit.Middleware.StateMachineSagaMessageFilter`2.Send(SagaConsumeContext`2 context, IPipe`1 next) in /_/src/MassTransit/Middleware/StateMachineSagaMessageFilter.cs:line 104
at MassTransit.Middleware.SendSagaPipe`2.Send(SagaRepositoryContext`2 context) in /_/src/MassTransit/Middleware/SendSagaPipe.cs:line 43
at MassTransit.Middleware.SendSagaPipe`2.Send(SagaRepositoryContext`2 context) in /_/src/MassTransit/Middleware/SendSagaPipe.cs:line 67
at MassTransit.Saga.InMemorySagaRepositoryContextFactory`1.Send[T](ConsumeContext`1 context, IPipe`1 next) in /_/src/MassTransit/Sagas/Saga/InMemoryRepository/InMemorySagaRepositoryContextFactory.cs:line 40
at MassTransit.DependencyInjection.DependencyInjectionSagaRepositoryContextFactory`1.Send[T](ConsumeContext`1 context, Func`3 send) in /_/src/MassTransit/DependencyInjection/DependencyInjection/DependencyInjectionSagaRepositoryContextFactory.cs:line 101
at MassTransit.DependencyInjection.DependencyInjectionSagaRepositoryContextFactory`1.Send[T](ConsumeContext`1 context, Func`3 send) in /_/src/MassTransit/DependencyInjection/DependencyInjection/DependencyInjectionSagaRepositoryContextFactory.cs:line 110
at MassTransit.Middleware.CorrelatedSagaFilter`2.Send(ConsumeContext`1 context, IPipe`1 next) in /_/src/MassTransit/Middleware/CorrelatedSagaFilter.cs:line 45
I tried looking for a solution on the internet and moving events to other states or adding the state to the instancestate, but nothing helped.
The Final
state is meant to be a terminal state, and once a state machine transitions to the Final
state, it should not accept any more events.
DataReport
event in the Final
state, which is not allowed.During(ClearDataState,
When(DataCalculated)
.Publish(x => new DeleteCalculateData() { RequestId = x.Message.RequestId })
.Finalize(),
// Move the logic to handle DataReport to a state before Final state
When(DataReport)
.Publish(x => new DeleteCalculateData() { RequestId = x.Message.RequestId })
);
CompositeEvent(() => Finished,
x => x.ReadyEventStatus,
CompositeEventOptions.IncludeInitial,
DataRequested,
DataRunning,
DataCalculated,
// Add DataReport to the CompositeEvent
DataReport
);
During(Initial,
When(Finished)
.Publish(context => new DataFinished() { RequestId = context.Saga.RequestId })
.Finalize()
);
DataReport
in the ClearDataState
is to perform some finalization logic, you can move that logic to a different state that comes before the Final
state.If the purpose of handling DataReport
in the ClearDataState
is to perform some finalization logic, you can move that logic to a different state that comes before the Final
state.ClearDataState
state, it handles the DataCalculated
and DataReport
events, publishing the corresponding messages and finalizing the state.Finished
event is received during the Initial
state, it publishes a DataFinished
message and finalizes the state.