public Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (LearningSynchronizedStorageSession)session; storageSession.Complete(sagaData); return(Task.CompletedTask); }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where TSagaData : IContainSagaData { var sql = @" SELECT data FROM sagas WHERE id = @Id "; var storageSession = session.PostgreSqlSession(); using (var command = new NpgsqlCommand(sql, storageSession.Connection, storageSession.Transaction)) { command.Parameters.AddWithValue("Id", sagaId); using (var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow)) { if (!await reader.ReadAsync()) { return(default(TSagaData)); } var json = reader.GetString(0); TSagaData sagaData = JsonConvert.DeserializeObject <TSagaData>(json); return(sagaData); } } }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where TSagaData : IContainSagaData { var operations = new SagaPersisterAtomicOperations(session); var incomingMessage = context.Get <IncomingMessage>(); var messageId = incomingMessage.MessageId; var indexStream = BuildSagaByIdStreamName(typeof(TSagaData), sagaId); var slice = await session.ReadStreamEventsBackwardAsync(indexStream, -1, 1, true).ConfigureAwait(false); if (slice.Status != SliceReadStatus.Success) { return(default(TSagaData)); } if (slice.Events[0].Event.EventType != SagaIndexEventType) { return(await operations.ReadSagaData <TSagaData>(indexStream, slice.Events[0], messageId)); } var indexEntry = slice.Events[0].Event.Data.ParseJson <SagaIndexEvent>(); var dataStream = indexEntry.DataStreamName; slice = await session.ReadStreamEventsBackwardAsync(dataStream, -1, 1, true).ConfigureAwait(false); if (slice.Status != SliceReadStatus.Success) { return(default(TSagaData)); } var sagaData = await operations.ReadSagaData <TSagaData>(dataStream, slice.Events[0], messageId); // ReSharper disable once CompareNonConstrainedGenericWithNull if (sagaData != null) { return(sagaData); } throw new Exception($"Either the saga has not yet been created successfully or saga ID {sagaId} has been sent out in a ghost message."); }
public TDbContext GetDataContext(SynchronizedStorageSession storageSession) { var dbConnection = storageSession.SqlPersistenceSession().Connection; if (_log.IsEnabled(LogEventLevel.Verbose)) { _log.Verbose($"Creating {typeof(TDbContext).FullName} context"); } var dbContext = DbContextThreadAsyncFactory.CreateDbContext(dbConnection, _schema, _builder.Build <TDbContext>); // Use the same underlying ADO.NET transaction dbContext.Database.UseTransaction(storageSession.SqlPersistenceSession().Transaction); // Call SaveChanges before completing storage session storageSession.SqlPersistenceSession().OnSaveChanges(x => { if (_log.IsEnabled(LogEventLevel.Verbose)) { _log.Verbose($"Auto saving changes for {typeof(TDbContext).FullName} context"); } return(dbContext.SaveChangesAsync()); }); return(dbContext); }
internal async Task Save(IContainSagaData sagaData, SynchronizedStorageSession session, object correlationId) { var sqlSession = session.SqlPersistenceSession(); var sagaInfo = sagaInfoCache.GetInfo(sagaData.GetType()); using (var command = sqlDialect.CreateCommand(sqlSession.Connection)) { command.Transaction = sqlSession.Transaction; command.CommandText = sagaInfo.SaveCommand; command.AddParameter("Id", sagaData.Id); var metadata = new Dictionary <string, string>(); if (sagaData.OriginalMessageId != null) { metadata.Add("OriginalMessageId", sagaData.OriginalMessageId); } if (sagaData.Originator != null) { metadata.Add("Originator", sagaData.Originator); } command.AddParameter("Metadata", Serializer.Serialize(metadata)); command.AddJsonParameter("Data", sqlDialect.BuildSagaData(command, sagaInfo, sagaData)); command.AddParameter("PersistenceVersion", StaticVersions.PersistenceVersion); command.AddParameter("SagaTypeVersion", sagaInfo.CurrentVersion); if (correlationId != null) { command.AddParameter("CorrelationId", correlationId); } AddTransitionalParameter(sagaData, sagaInfo, command); await command.ExecuteNonQueryEx().ConfigureAwait(false); } }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where TSagaData : IContainSagaData { var sagas = await GetSagasDictionary().ConfigureAwait(false); var secondaryIndex = await GetIndexDicitonary().ConfigureAwait(false); using (var tx = stateManager.CreateTransaction()) { var correlationId = await secondaryIndex.TryGetValueAsync(tx, sagaId, LockMode.Default).ConfigureAwait(false); if (correlationId.HasValue == false) { return(default(TSagaData)); } var sagaData = await sagas.TryGetValueAsync(tx, correlationId.Value, LockMode.Default).ConfigureAwait(false); if (sagaData.HasValue == false) { throw new Exception($"Failed to update saga data for SagaId='{sagaId}' and CorrelationId='{correlationId.Value}'"); } return(Resolve <TSagaData>(sagaData.Value, context)); } }
public Task <T> Get <T>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); return(documentSession.LoadAsync <T>(sagaId)); }
public async Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { var sagas = await GetSagasDictionary().ConfigureAwait(false); var secondaryIndex = await GetIndexDicitonary().ConfigureAwait(false); using (var tx = stateManager.CreateTransaction()) { var sagaId = sagaData.Id; var correlationId = await GetCorrelationId(secondaryIndex, tx, sagaId).ConfigureAwait(false); await secondaryIndex.TryRemoveAsync(tx, sagaId).ConfigureAwait(false); var previouslyExistingState = await sagas.TryRemoveAsync(tx, correlationId).ConfigureAwait(false); if (previouslyExistingState.HasValue == false) { throw new Exception($"Failed to complete saga data for SagaId='{sagaId}' and CorrelationId='{correlationId}'"); } var dataAtReading = context.Get <Metadata>().SagaData[sagaId]; var dataAtDeletion = previouslyExistingState.Value; if (Compare(dataAtReading, dataAtDeletion) == false) { throw new Exception($"Optimistic concurrency failure for SagaId='{sagaId}' and CorrelationId='{correlationId}'"); } await tx.CommitAsync().ConfigureAwait(false); } }
public async Task Update(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { var sagas = await GetSagasDictionary().ConfigureAwait(false); var secondaryIndex = await GetIndexDicitonary().ConfigureAwait(false); using (var tx = stateManager.CreateTransaction()) { var sagaId = sagaData.Id; var correlationId = await GetCorrelationId(secondaryIndex, tx, sagaId).ConfigureAwait(false); var data = Serialize(sagaData); var previousData = context.Get <Metadata>().SagaData[sagaData.Id]; var result = await sagas.TryUpdateAsync(tx, correlationId, data, previousData); if (result == false) { throw new Exception($"Optimistic concurrency failure for SagaId='{sagaData.Id}' and CorrelationId='{sagaId}'"); } await tx.CommitAsync(); } }
public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue); //store it in the context to be able to optimize deletes for legacy sagas that don't have the id in metadata context.Set(UniqueDocIdKey, lookupId); var lookup = await documentSession .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip .LoadAsync <SagaUniqueIdentity>(lookupId) .ConfigureAwait(false); if (lookup != null) { documentSession.Advanced.Evict(lookup); return(lookup.SagaDocId != null ? await documentSession.LoadAsync <T>(lookup.SagaDocId).ConfigureAwait(false) //if we have a saga id we can just load it : await Get <T>(lookup.SagaId, session, context).ConfigureAwait(false)); //if not this is a saga that was created pre 3.0.4 so we fallback to a get instead } return(default(T)); }
Task <T> ISagaPersister.Get <T>(string property, object value, SynchronizedStorageSession session, ContextBag context) { return(session.Session().CreateCriteria(typeof(T)) .SetLockMode(GetLockModeForSaga <T>()) .Add(Restrictions.Eq(property, value)) .UniqueResultAsync <T>()); }
static Task SaveSagaWithoutCorrelationProperty(IContainSagaData sagaData, SynchronizedStorageSession session) { var indexStream = BuildSagaByIdStreamName(sagaData.GetType(), sagaData.Id); var stateChangeEvent = new EventData(Guid.NewGuid(), SagaDataEventType, true, sagaData.ToJsonBytes(), new byte[0]); return(session.AppendToStreamAsync(indexStream, ExpectedVersion.NoStream, stateChangeEvent)); }
public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue); var lookup = await documentSession .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip .LoadAsync <SagaUniqueIdentity>(lookupId) .ConfigureAwait(false); if (lookup != null) { documentSession.Advanced.Evict(lookup); // If we have a saga id we can just load it, should have been included in the round-trip already var container = await documentSession.LoadAsync <SagaDataContainer>(lookup.SagaDocId).ConfigureAwait(false); if (container != null) { if (container.IdentityDocId == null) { container.IdentityDocId = lookupId; } context.Set($"{SagaContainerContextKeyPrefix}{container.Data.Id}", container); return((T)container.Data); } } return(default(T)); }
public async Task <TSagaData> Get <TSagaData>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where TSagaData : class, IContainSagaData { var result = await Get <TSagaData>(sagaId, session).ConfigureAwait(false); return(SetConcurrency(result, context)); }
public async Task <ClientOutboxMessageV2> GetAsync(Guid messageId, SynchronizedStorageSession synchronizedStorageSession) { var sqlStorageSession = synchronizedStorageSession.GetSqlStorageSession(); using (var command = sqlStorageSession.Connection.CreateCommand()) { command.CommandText = GetCommandText; command.CommandType = CommandType.Text; command.Transaction = sqlStorageSession.Transaction; command.AddParameter("MessageId", messageId); using (var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow).ConfigureAwait(false)) { if (await reader.ReadAsync().ConfigureAwait(false)) { var endpointName = reader.GetString(0); var transportOperations = JsonConvert.DeserializeObject <List <TransportOperation> >(reader.GetString(1), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); var clientOutboxMessage = new ClientOutboxMessageV2(messageId, endpointName, transportOperations); return(clientOutboxMessage); } throw new KeyNotFoundException($"Client outbox data not found where MessageId = '{messageId}'"); } } }
public Task <T> Get <T>(Guid sagaId, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var result = session.Session().Get <T>(sagaId, GetLockModeForSaga <T>()); return(Task.FromResult(result)); }
public async Task Save( IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var sagaTypeName = sagaData.GetType().Name; var sagaDataWithVersion = sagaData as IHaveDocumentVersion; if (sagaDataWithVersion == null) { throw new InvalidOperationException( string.Format("Saga type {0} does not implement IHaveDocumentVersion", sagaTypeName)); } sagaDataWithVersion.DocumentVersion = 0; sagaDataWithVersion.ETag = sagaData.ComputeETag(); if (correlationProperty != null) { await this.EnsureUniqueIndex(sagaData, correlationProperty).ConfigureAwait(false); } var collection = this.mongoDatabase.GetCollection <BsonDocument>(sagaTypeName); await collection.InsertOneAsync(sagaData.ToBsonDocument()).ConfigureAwait(false); }
public Task <TestSaga08.SagaData08> FindBy(SomeOtherMessage message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context) { Context.FinderUsed = true; var bag = new ContextBag(); bag.Set(context.Get <IncomingMessage>()); return(SagaPersister.Get <TestSaga08.SagaData08>("Property", "Test", storageSession, bag)); }
public ReceiverDataContext GetDataContext(SynchronizedStorageSession storageSession) { if (context == null) { context = contextFactory(storageSession); } return(context); }
public Task <OrderSagaData> FindBy(StartOrder message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context) { var session = storageSession.RavenSession(); // if the instance is null a new saga will be automatically created if // the Saga handles the message as IAmStartedByMessages<StartOrder>; otherwise an exception is raised. return(session.LoadByUniqueConstraintAsync <OrderSagaData>(d => d.OrderId, message.OrderId)); }
static StorageSession GetSqlStorageSession(this SynchronizedStorageSession session) { if (session is StorageSession storageSession) { return(storageSession); } throw new Exception("Cannot access the SQL synchronized storage session. Either this endpoint has not been configured to use the SQL persistence or a different persistence type is used for sagas."); }
public Task <TweetReceivedSagaData> FindBy(TweetReceived message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context) { var tweetReceivedSagaData = storageSession.Session().QueryOver <TweetReceivedSagaData>() .Where(d => d.Hashtag == message.Track) .SingleOrDefault(); return(Task.FromResult(tweetReceivedSagaData)); }
public Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { var query = Builders <BsonDocument> .Filter.Eq(MongoPersistenceConstants.IdPropertyName, sagaData.Id); var collection = this.mongoDatabase.GetCollection <BsonDocument>(sagaData.GetType().Name); return(collection.DeleteOneAsync(query)); }
public Task <OrderSagaData> FindBy(CompleteOrder message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context) { var orderSagaData = storageSession.Session().QueryOver <OrderSagaData>() .Where(d => d.OrderId == message.OrderId) .SingleOrDefault(); return(Task.FromResult(orderSagaData)); }
public Task Complete(IContainSagaData sagaData, SynchronizedStorageSession session, ContextBag context) { var documentSession = session.MartenSession(); documentSession.Delete <SagaDocument>(sagaData.Id); return(Task.CompletedTask); }
public Task<MySagaData> FindBy(MyMessage message, SynchronizedStorageSession storageSession, ReadOnlyContextBag context) { // SynchronizedStorageSession will have a persistence specific extension method // For example purposes GetDbSession is a stub extension method var dbSession = storageSession.GetDbSession(); return dbSession.GetSagaFromDB(message.SomeId, message.SomeData); // If a saga can't be found Task.FromResult(null) should be returned }
static StorageSession GetSqlStorageSession(this SynchronizedStorageSession session) { if (session is StorageSession storageSession) { return(storageSession); } throw new Exception("The endpoint has not been configured to use SQL persistence."); }
public static ISqlStorageSession GetSqlSession(this SynchronizedStorageSession synchronizedStorageSession) { if (synchronizedStorageSession is ISqlStorageSession sqlSession) { return(sqlSession); } throw new Exception("Cannot access the SQL session"); }
public InvokeHandlerContext(MessageHandler handler, string messageId, string replyToAddress, Dictionary<string, string> headers, MessageMetadata messageMetadata, object messageBeingHandled, SynchronizedStorageSession storageSession, IBehaviorContext parentContext) : base(messageId, replyToAddress, headers, parentContext) { MessageHandler = handler; Headers = headers; MessageBeingHandled = messageBeingHandled; MessageMetadata = messageMetadata; Set(storageSession); }
public Task <SagaFinderSagaData> FindBy(StartSagaMessage message, SynchronizedStorageSession session, ReadOnlyContextBag options, CancellationToken cancellationToken = default) { if (Context.SagaId == Guid.Empty) { return(Task.FromResult(default(SagaFinderSagaData))); } return(session.RavenSession().LoadAsync <SagaFinderSagaData>(Context.SagaId.ToString(), cancellationToken)); }
/// <summary> /// Gets the current context NHibernate <see cref="ISession"/>. /// </summary> public static ISession Session(this SynchronizedStorageSession session) { var ambientTransactionSession = session as INHibernateSynchronizedStorageSession; if (ambientTransactionSession != null) { return ambientTransactionSession.Session; } throw new InvalidOperationException("Shared session has not been configured for NHibernate."); }
internal InvokeHandlerContext(MessageHandler handler, SynchronizedStorageSession storageSession, IIncomingLogicalMessageContext parentContext) : this(handler, parentContext.MessageId, parentContext.ReplyToAddress, parentContext.Headers, parentContext.Message.Metadata, parentContext.Message.Instance, storageSession, parentContext) { }
public abstract Task<IContainSagaData> Find(IBuilder builder, SagaFinderDefinition finderDefinition, SynchronizedStorageSession storageSession, ContextBag context, object message);