I would like to use unique natural key instead of build in Guid CorrelationId in Masstransit Sagas. However it seems not really work. If I send twice Initial event with same key value, two Sagas created in repository - expected is single instance. Same scenario with using CorrelationId produces one Saga instance in repository.
Any ideas, why second Saga instance created with same key, ignoring correlation statement?
Here is short example with unit test:
[TestFixture]
public class SagaTests
{
[Test]
public void TestSagaInitialization()
{
var testSaga = new TestSaga();
var testSagaRepository = new InMemorySagaRepository<TestSagaState>();
var busControl = Bus.Factory.CreateUsingInMemory(
cfg =>
{
cfg.ReceiveEndpoint("test_queue",
e =>
{
e.StateMachineSaga(testSaga, testSagaRepository);
});
});
busControl.Start();
busControl.Publish(new TestSagaInitEvent() { UniqueNaturalKey = 1 }).Wait();
busControl.Publish(new TestSagaInitEvent() { UniqueNaturalKey = 2 }).Wait();
// Message with same natural key published again
busControl.Publish(new TestSagaInitEvent() { UniqueNaturalKey = 1 }).Wait();
// Wait till all messges consumed
var till = DateTime.Now.AddSeconds(1);
while (DateTime.Now < till) { System.Threading.Thread.Sleep(50); }
busControl.Stop();
var sagaInstances = testSagaRepository.Where(x => x.UniqueNaturalKey == 1).Result.ToList();
Assert.AreEqual(1, sagaInstances.Count, "Dublicate initial events with same Natural Key value must not create new Saga instance");
}
}
public class TestSagaState : Automatonymous.SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public int CurrentState { get; set; }
public long UniqueNaturalKey { get; set; }
}
public class TestSaga : MassTransitStateMachine<TestSagaState>
{
public TestSaga()
{
InstanceState(x => x.CurrentState);
Event(() => SagaInitiated, x => x.CorrelateById(state => state.UniqueNaturalKey, context => context.Message.UniqueNaturalKey)
.SelectId(context => Guid.NewGuid()));
Initially(
When(SagaInitiated)
.Then(context =>
{
context.Instance.UniqueNaturalKey = context.Data.UniqueNaturalKey;
})
.TransitionTo(Initiated)
);
}
public State Initiated { get; private set; }
public Event<TestSagaInitEvent> SagaInitiated { get; private set; }
}
public class TestSagaInitEvent
{
public long UniqueNaturalKey { get; set; }
}