问题
My Saga message handler (configured as ISagaStartedBy) requests a timeout message for every message received.
Debugging through a few messages at a time, I've found the time the first time the handler is fired, the saga ID sent to the timeout manager is different to the one a) persisted in the database and b) the saga ID sent in subsequent messages. The subsequent messages all send the Saga ID from the database.
Here's the handler:
public void Handle(PaymentRequested message)
{
int timeoutMinutes = 3;
try
{
timeoutMinutes = int.Parse(ConfigurationManager.AppSettings["TimeoutMinutes"]);
}
catch (Exception ex)
{
// log errors
}
Data.PseudoSagaID = message.PseudoSagaID;
var child = new TransactionDetail()
{ // fields added}
Data.AddTransactionItem(message.TransactionItem);
RequestUtcTimeout(DateTime.UtcNow.AddMinutes(timeoutMinutes), "Saga ending");
}
I've also tried setting the Saga ID in the code but then it gets overwritten in the database when it gets saved when it exits the handler. I do have my own persister which as follows:
public class MySBASagaPersister : ISagaPersister, IDisposable
{
public MySBASagaPersister(ISessionFactory sessionFactory)
{
SessionFactory = sessionFactory;
Session = sessionFactory.OpenSession();
}
public ISessionFactory SessionFactory { get; set; }
public ISession Session { get; set; }
#region ISagaPersister Members
public void Save(ISagaEntity saga)
{
Session.Save(saga);
}
public void Update(ISagaEntity saga)
{
Session.Merge(saga);
}
public void UpdateWithDelete(ISagaEntity saga)
{
Session.Merge(saga);
}
public T Get<T>(Guid sagaId) where T : ISagaEntity
{
return Session.CreateCriteria(typeof(T), "b")
.Add(Restrictions.Eq("b.Id", sagaId))
.SetFetchMode("b.PaymentRequestedTransactionItems", FetchMode.Eager)
.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.UniqueResult<T>();
}
public T Get<T>(string property, object value) where T : ISagaEntity
{
return Session.CreateCriteria(typeof(T), "b")
.Add(Restrictions.Eq("b." + property, value))
.SetFetchMode("b.PaymentRequestedTransactionItems", FetchMode.Eager)
.UniqueResult<T>();
}
public void Complete(ISagaEntity saga)
{
Session.Delete(saga);
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
if (Session == null) return;
if (!Session.IsOpen) return;
Session.Close();
Session.Dispose();
}
#endregion
}
How can I check to see if the saga has been saved in the database? Or is this the wrong way to go about checking the true Saga ID? Or is my timeout request incorrect?
UPDATE:
public override void ConfigureHowToFindSaga()
{
// Map PaymentRequested message type.
ConfigureMapping<PaymentRequested>(
saga => saga.PseudoSagaID,
message => message.PseudoSagaID);
// Map PaymentCancelled message type.
ConfigureMapping<PaymentCancelled>(
saga => saga.PseudoSagaID,
message => message.PseudoSagaID);
}
The reason I don't pull the saga out of the database with the guid based Id is because there's only ever one saga active at a time hence the use of PseudoSagaID but it should still work the same way. If there's no saga present, one should be created and a new guid etc should be generated at that point and preseved. But that's not the case...
来源:https://stackoverflow.com/questions/9028331/why-does-nservicebus-saga-timeout-request-use-wrong-saga-id