Пример #1
0
        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);
    }
Пример #3
0
        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();
            }
        }
Пример #4
0
        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();
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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();
 }
Пример #16
0
        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>();
 }
Пример #19
0
        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;
        }
Пример #30
0
        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);
        }