public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { DocumentVersionAttribute.SetPropertyValue(sagaData, 0); await EnsureUniqueIndex(sagaData.GetType(), correlationProperty?.Name).ConfigureAwait(false); await _repo.Insert(sagaData).ConfigureAwait(false); }
public override async Task Invoke(IIncomingLogicalMessageContext context, Func <Task> next) { var correlationProperty = SagaCorrelationProperty.None; if (context.Message.Instance is IProvideOrderId provideOrderId) { var partitionKeyValue = provideOrderId.OrderId; correlationProperty = new SagaCorrelationProperty("OrderId", partitionKeyValue); } await partitionKeyFromSagaId1.SetPartitionKey <OrderSagaData>(context, correlationProperty); if (context.Headers.TryGetValue(Headers.SagaId, out var sagaIdHeader)) { Log.Info($"Saga Id Header: {sagaIdHeader}"); } if (context.Extensions.TryGet <TableInformation>(out var tableInformation)) { Log.Info($"Table Information: {tableInformation.TableName}"); } Log.Info($"Found partition key '{context.Extensions.Get<TableEntityPartitionKey>().PartitionKey}' from '{nameof(IProvideOrderId)}'"); await next().ConfigureAwait(false); }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { string sql = @" INSERT INTO sagas ( id, originator, originalmessageid, data ) VALUES ( @Id, @Originator, @OriginalMessageId, @Data ) "; var storageSession = session.PostgreSqlSession(); using (var command = new NpgsqlCommand(sql, storageSession.Connection, storageSession.Transaction)) { command.Parameters.AddWithValue("Id", sagaData.Id); command.Parameters.AddWithValue("Originator", sagaData.Originator); command.Parameters.AddWithValue("OriginalMessageId", sagaData.OriginalMessageId); var json = JsonConvert.SerializeObject(sagaData); command.Parameters.AddWithValue("Data", NpgsqlDbType.Jsonb, json); await command.ExecuteNonQueryAsync(); } }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var sagas = await GetSagasDictionary().ConfigureAwait(false); var secondaryIndex = await GetIndexDicitonary().ConfigureAwait(false); using (var tx = stateManager.CreateTransaction()) { var correlationId = BuildKey(correlationProperty); var data = Serialize(sagaData); var result = await sagas.TryAddAsync(tx, correlationId, data); if (result == false) { throw new Exception($"Failed to save new saga data for {correlationProperty.Name}='{correlationProperty.Value}'"); } result = await secondaryIndex.TryAddAsync(tx, sagaData.Id, correlationId); if (result == false) { throw new Exception($"Failed to save index for saga data for {correlationProperty.Name}='{correlationProperty.Value}'"); } await tx.CommitAsync(); } }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var documentSession = session.RavenSession(); if (sagaData == null) { return; } var container = new SagaDataContainer { Id = DocumentIdForSagaData(documentSession, sagaData), Data = sagaData }; if (correlationProperty == null) { return; } container.IdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value); await documentSession.StoreAsync(container, string.Empty, container.Id).ConfigureAwait(false); await documentSession.StoreAsync(new SagaUniqueIdentity { Id = container.IdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = container.Id }, changeVector : string.Empty, id : container.IdentityDocId).ConfigureAwait(false); }
void ValidateUniqueProperties(SagaCorrelationProperty correlationProperty, IContainSagaData saga) { var sagaType = saga.GetType(); var existingSagas = new List <VersionedSagaEntity>(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var s in data) { if (s.Value.SagaData.GetType() == sagaType && (s.Key != saga.Id)) { existingSagas.Add(s.Value); } } var uniqueProperty = sagaType.GetProperty(correlationProperty.Name); if (correlationProperty.Value == null) { var message = $"Cannot store saga with id '{saga.Id}' since the unique property '{uniqueProperty.Name}' has a null value."; throw new InvalidOperationException(message); } foreach (var storedSaga in existingSagas) { var storedSagaPropertyValue = uniqueProperty.GetValue(storedSaga.SagaData, null); if (Equals(correlationProperty.Value, storedSagaPropertyValue)) { var message = $"Cannot store a saga. The saga with id '{storedSaga.SagaData.Id}' already has property '{uniqueProperty.Name}'."; throw new InvalidOperationException(message); } } }
public async Task Should_query_by_saga_type() { var otherSaga = new SomeOtherSagaData { Id = Guid.NewGuid(), SomeId = "test-id", SomeName = "Test Name" }; var saga = new SagaData { Id = Guid.NewGuid(), SomeId = "test-id", SomeName = "Test Name" }; IDocumentSession session; var context = this.CreateContextWithSessionPresent(out session); var sagaPersister = new SagaPersister(); var synchronizedStorageSession = new MartenSynchronizedStorageSession(session, true); var correlationProperty = new SagaCorrelationProperty("SomeId", saga.SomeId); await sagaPersister.Save(otherSaga, correlationProperty, synchronizedStorageSession, context); await sagaPersister.Save(saga, correlationProperty, synchronizedStorageSession, context); await session.SaveChangesAsync().ConfigureAwait(false); var savedSaga = await sagaPersister.Get <SagaData>(correlationProperty.Name, correlationProperty.Value, synchronizedStorageSession, context); savedSaga.Id.Should().Be(saga.Id); }
public async Task The_database_should_enforce_the_uniqueness() { var failed = false; using (var session = SessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { var correlationProperty = new SagaCorrelationProperty("UniqueString", "whatever"); var storageSession = new TestingNHibernateSynchronizedStorageSession(session); await SagaPersister.Save(new SagaWithUniqueProperty { Id = Guid.NewGuid(), UniqueString = "whatever" }, correlationProperty, storageSession, new ContextBag()).ConfigureAwait(false); await SagaPersister.Save(new SagaWithUniqueProperty { Id = Guid.NewGuid(), UniqueString = "whatever" }, correlationProperty, storageSession, new ContextBag()).ConfigureAwait(false); try { transaction.Commit(); } catch (Exception) { failed = true; } } Assert.IsTrue(failed); }
public TSaga GetSagaByCorrelationId <TSaga>(SagaCorrelationProperty id) where TSaga : SagaBase { var sagaType = typeof(TSaga).Name; using (var db = _contextFactory()) { var sagaCorrelationId = db .SagaCorrelationIds .Include(s => s.Saga) .FirstOrDefault(s => s.PropertyValue == id.PropertyValue && s.PropertyName == id.PropertyName && s.SagaType == sagaType); if (sagaCorrelationId == null) { return(null); } var saga = _sagaFactory.GetSaga <TSaga>(); if (saga == null) { //todo: throw } else { saga.LoadSagaData(sagaCorrelationId.Saga.ToSagaState()); } return(saga); } }
public Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (LearningSynchronizedStorageSession)session; storageSession.Save(sagaData); return(Task.CompletedTask); }
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 async Task Setup() { entity = new PropertyTypesTestSagaData { Id = Guid.NewGuid(), TestComponent = new TestComponent { Property = "Prop" }, DateTimeProperty = DateTime.Parse("12/02/2010 12:00:00.01").ToUniversalTime(), Status = Statuses.AnotherStatus, PolymorphicRelatedProperty = new PolymorphicProperty { SomeInt = 9 }, RelatedClass = new RelatedClass { Id = Guid.NewGuid() } }; relatedClass = entity.RelatedClass; var insertContextBag = configuration.GetContextBagForSagaStorage(); using (var insertSession = await configuration.SynchronizedStorage.OpenSession(insertContextBag)) { var correlationProperty = new SagaCorrelationProperty(nameof(entity.Id), entity.Id); await configuration.SagaStorage.Save(entity, correlationProperty, insertSession, insertContextBag); await insertSession.CompleteAsync(); } savedEntity = await GetById <PropertyTypesTestSagaData>(entity.Id).ConfigureAwait(false); }
public Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var partitionKey = GetPartitionKey(context, sagaData.Id); storageSession.AddOperation(new SagaSave(sagaData, partitionKey, serializer, context)); return(Task.CompletedTask); }
public Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var operations = new SagaPersisterAtomicOperations(session); return(correlationProperty != null ? SaveSagaWithCorrelationProperty(sagaData, correlationProperty, operations, session) : SaveSagaWithoutCorrelationProperty(sagaData, session)); }
public void RetrievingSagaUsingIdNotFound( MongoSagaPersister sut, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Get <SagaWithUniqueProperty>(sagaData.Id, session, context).Result.Should().BeNull(); }
public void SaveSagaData( MongoSagaPersister sut, DeviceCommandSagaState state, SynchronizedStorageSession session, ContextBag context) { var correlationProperty = new SagaCorrelationProperty("SagaKey", state.SagaKey); sut.Save(state, correlationProperty, session, context).Wait(); }
public void RetrievingSagaUsingCorrelationPropertyNotFound( MongoSagaPersister sut, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Get <SagaWithUniqueProperty>(correlationProperty.Name, "badvalue", session, context) .Result.Should() .BeNull(); }
public void UpdatingSagaWithoutDocumentVersion( MongoSagaPersister sut, MongoDatabaseFactory factory, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Invoking(s => s.Update(sagaData, session, context).Wait()).ShouldThrow <InvalidOperationException>(); }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, ISynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var storageSession = (StorageSession)session; var sagaDataType = sagaData.GetType(); var document = sagaData.ToBsonDocument(); document.Add(versionElementName, 0); await storageSession.InsertOneAsync(sagaDataType, document, cancellationToken).ConfigureAwait(false); }
protected Task SaveSaga <T>(T saga) where T : IContainSagaData { SagaCorrelationProperty correlationProperty = null; if (saga.GetType() == typeof(SagaWithUniqueProperty)) { correlationProperty = new SagaCorrelationProperty("UniqueString", String.Empty); } return(_sagaPersister.Save(saga, correlationProperty, null, null)); }
static async Task SaveSagaWithCorrelationProperty(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SagaPersisterAtomicOperations operations, SynchronizedStorageSession session) { var propertyValue = correlationProperty.Value; var indexStream = BuildSagaByIdStreamName(sagaData.GetType(), sagaData.Id); var dataStream = BuildSagaDataStreamName(sagaData.GetType(), propertyValue); var stateChangeEvent = new EventData(Guid.NewGuid(), SagaDataEventType, true, sagaData.ToJsonBytes(), new byte[0]); await operations.CreateIndex(indexStream, dataStream).ConfigureAwait(false); await session.AppendToStreamAsync(dataStream, ExpectedVersion.NoStream, stateChangeEvent).ConfigureAwait(false); }
public void UpdatingNonExistantSagaWithUniqueProperty( MongoSagaPersister sut, MongoDatabaseFactory factory, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Invoking(s => s.Update(sagaData, session, context).Wait()).ShouldThrow <InvalidOperationException>(); factory.RetrieveSagaData(sagaData).Should().BeNull(); }
public void InterleavedSavingSagaShouldThrowException( MongoSagaPersister sut, MongoDatabaseFactory factory, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Save(sagaData, correlationProperty, session, context).Wait(); sut.Invoking(s => s.Save(sagaData, correlationProperty, session, context).Wait()) .ShouldThrow <MongoWriteException>(); }
public void CompletingSagaShouldRemoveDocument( MongoSagaPersister sut, MongoDatabaseFactory factory, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Save(sagaData, correlationProperty, session, context).Wait(); sut.Complete(sagaData, session, context).Wait(); factory.RetrieveSagaData(sagaData).Should().BeNull(); }
public void RetrievingSagaUsingId( MongoSagaPersister sut, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Save(sagaData, correlationProperty, session, context).Wait(); var result = sut.Get <SagaWithUniqueProperty>(sagaData.Id, session, context).Result; result.ShouldBeEquivalentTo(sagaData); }
public static SagaCorrelationProperty CreateMetadata <T>(this RavenDBPersistenceTestBase test, IContainSagaData sagaEntity) { var metadata = SagaMetadata.Create(typeof(T)); SagaMetadata.CorrelationPropertyMetadata correlationPropertyMetadata; metadata.TryGetCorrelationProperty(out correlationPropertyMetadata); var propertyInfo = metadata.SagaEntityType.GetProperty(correlationPropertyMetadata.Name); var value = propertyInfo.GetValue(sagaEntity); var correlationProperty = new SagaCorrelationProperty(correlationPropertyMetadata.Name, value); return(correlationProperty); }
private async Task EnsureUniqueIndex(IContainSagaData saga, SagaCorrelationProperty correlationProperty) { Contract.Requires(saga != null); Contract.Requires(correlationProperty != null); var collection = this.mongoDatabase.GetCollection <BsonDocument>(saga.GetType().Name); await collection.Indexes.CreateOneAsync( new BsonDocumentIndexKeysDefinition <BsonDocument>(new BsonDocument(correlationProperty.Name, 1)), new CreateIndexOptions() { Unique = true }).ConfigureAwait(false); }
public void SavingSagaWithUniqueProperty( MongoSagaPersister sut, MongoDatabaseFactory factory, SagaWithUniqueProperty sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { sut.Save(sagaData, correlationProperty, session, context).Wait(); var entity = factory.RetrieveSagaData(sagaData); entity.Id.Should().Be(sagaData.Id); entity.UniqueProperty.Should().Be(sagaData.UniqueProperty); entity.SomeValue.Should().Be(sagaData.SomeValue); }
static async Task CreateSagaUniqueIdentity(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, IAsyncDocumentSession documentSession) { var sagaDocId = documentSession.Advanced.DocumentStore.Conventions.FindFullDocumentKeyFromNonStringIdentifier(sagaData.Id, sagaData.GetType(), false); var sagaUniqueIdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value); await documentSession.StoreAsync(new SagaUniqueIdentity { Id = sagaUniqueIdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = sagaDocId }, id : sagaUniqueIdentityDocId, etag : Etag.Empty).ConfigureAwait(false); var metadata = await documentSession.Advanced.GetMetadataForAsync(sagaData).ConfigureAwait(false); metadata[UniqueDocIdKey] = sagaUniqueIdentityDocId; }
protected SagaCorrelationProperty GetSagaCorrelationProperty <TSagaData>(TSagaData sagaData) { var sagaMetadata = configuration.SagaMetadataCollection.FindByEntity(typeof(TSagaData)); var correlationProperty = SagaCorrelationProperty.None; if (sagaMetadata.TryGetCorrelationProperty(out var correlatedProp)) { var prop = sagaData.GetType().GetProperty(correlatedProp.Name); var value = prop.GetValue(sagaData); correlationProperty = new SagaCorrelationProperty(correlatedProp.Name, value); } return(correlationProperty); }