public void It_should_persist_successfully()
    {
        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister    = new SagaPersister(factory);
            var uniqueString = Guid.NewGuid().ToString();
            var saga1        = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };
            persister.Save(saga1);
            factory.SaveChanges();
            factory.ReleaseSession();

            var saga = persister.Get <SagaData>(saga1.Id);
            persister.Complete(saga);
            factory.SaveChanges();
            factory.ReleaseSession();

            var saga2 = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };

            persister.Save(saga2);
            factory.SaveChanges();
        }
    }
Ejemplo n.º 2
0
    public async Task Should_delete_the_saga_and_the_unique_doc()
    {
        var sagaId = Guid.NewGuid();

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister = new SagaPersister();
            var entity    = new SagaData
            {
                Id = sagaId
            };
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session);

            await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);

            var saga = await persister.Get <SagaData>(sagaId, synchronizedSession, options);

            await persister.Complete(saga, synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);

            Assert.Null(await persister.Get <SagaData>(sagaId, synchronizedSession, options));
            Assert.Null(await session.Query <SagaUniqueIdentity>().Customize(c => c.WaitForNonStaleResults()).SingleOrDefaultAsync(u => u.SagaId == sagaId).ConfigureAwait(false));
        }
    }
Ejemplo n.º 3
0
    public async Task Public_setters_and_getters_of_concrete_classes_should_be_persisted()
    {
        var entity = new SagaData
        {
            Id            = Guid.NewGuid(),
            UniqueString  = "SomeUniqueString",
            TestComponent = new TestComponent
            {
                Property = "Prop"
            }
        };

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister           = new SagaPersister(new SagaPersistenceConfiguration());
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options);

            await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);

            var savedEntity = await persister.Get <SagaData>(entity.Id, synchronizedSession, options);

            Assert.AreEqual(entity.TestComponent.Property, savedEntity.TestComponent.Property);
            Assert.AreEqual(entity.TestComponent.AnotherProperty, savedEntity.TestComponent.AnotherProperty);
        }
    }
    public void It_should_allow_the_update()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var uniqueString = Guid.NewGuid().ToString();
        var saga1 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString
            };

        persister.Save(saga1);
        factory.SaveChanges();
        factory.ReleaseSession();

        var saga = persister.Get<SagaData>(saga1.Id);
        saga.UniqueString = Guid.NewGuid().ToString();
        persister.Update(saga);
        factory.SaveChanges();
        factory.ReleaseSession();

        var saga2 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString
            };

        //this should not blow since we changed the unique value in the previous saga
        persister.Save(saga2);
        factory.SaveChanges();
    }
Ejemplo n.º 5
0
        public void When_initiating_message_can_not_be_found_doesnot_throw()
        {
            var sagaId   = Guid.NewGuid();
            var timeouts = new List <SagaTimeoutMessage> {
                new SagaTimeoutMessage {
                    DeliverAt = DateTime.Now, Timeout = TimeSpan.FromMinutes(1)
                }
            };
            var update = new SagaUpdate {
                InitiatingMessage = null, OutgoingMessages = timeouts
            };

            var sagaChanges = new List <SagaUpdate> {
                update
            };
            var sagaList = new List <SagaInfo> {
                new SagaInfo {
                    SagaId = sagaId
                }
            };
            var sagaData = new SagaData {
                Changes = sagaChanges
            };

            messageSelectionContext.SelectedMessage = new StoredMessage {
                InvokedSagas = sagaList
            };
            serviceControl.GetSagaById(Arg.Is(sagaId)).Returns(sagaData);
            var selectedMessageChanged = new SelectedMessageChanged();

            Assert.DoesNotThrowAsync(() => viewModel.Handle(selectedMessageChanged));
        }
Ejemplo n.º 6
0
    public async Task Schema_version_should_be_persisted()
    {
        // arrange
        var entity = new SagaData
        {
            Id           = Guid.NewGuid(),
            UniqueString = "SomeUniqueString",
        };

        var persister = new SagaPersister();

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var context))
        {
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session);

            // act
            await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, context);

            await session.SaveChangesAsync();

            // assert
            var sagaDataContainerId = SagaPersister.DocumentIdForSagaData(session, entity);
            var sagaDataContainer   = await session.LoadAsync <SagaDataContainer>(sagaDataContainerId);

            var sagaDataContainerMetadata = session.Advanced.GetMetadataFor(sagaDataContainer);

            var sagaUniqueIdentityId = sagaDataContainer.IdentityDocId;
            var sagaUniqueIdentity   = await session.LoadAsync <SagaUniqueIdentity>(sagaUniqueIdentityId);

            var sagaUniqueIdentityMetadata = session.Advanced.GetMetadataFor(sagaUniqueIdentity);

            Assert.AreEqual(SagaDataContainer.SchemaVersion, sagaDataContainerMetadata[SchemaVersionExtensions.SagaDataContainerSchemaVersionMetadataKey]);
            Assert.AreEqual(SagaUniqueIdentity.SchemaVersion, sagaUniqueIdentityMetadata[SchemaVersionExtensions.SagaUniqueIdentitySchemaVersionMetadataKey]);
        }
    }
    public void It_should_persist_successfully()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var uniqueString = Guid.NewGuid().ToString();
        var saga1 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString
            };
        persister.Save(saga1);
        factory.SaveChanges();
        factory.ReleaseSession();

        var saga = persister.Get<SagaData>(saga1.Id);
        persister.Complete(saga);
        factory.SaveChanges();
        factory.ReleaseSession();

        var saga2 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString
            };

        persister.Save(saga2);
        factory.SaveChanges();
    }
    public void It_should_allow_the_update()
    {
        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister    = new SagaPersister(factory);
            var uniqueString = Guid.NewGuid().ToString();
            var saga1        = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };

            persister.Save(saga1);
            factory.SaveChanges();
            factory.ReleaseSession();

            var saga = persister.Get <SagaData>(saga1.Id);
            saga.UniqueString = Guid.NewGuid().ToString();
            persister.Update(saga);
            factory.SaveChanges();
            factory.ReleaseSession();

            var saga2 = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };

            //this should not blow since we changed the unique value in the previous saga
            persister.Save(saga2);
            factory.SaveChanges();
        }
    }
    public void It_should_enforce_uniqueness()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var uniqueString = Guid.NewGuid().ToString();

        var saga1 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString
            };

        persister.Save(saga1);
        factory.SaveChanges();
        factory.ReleaseSession();

        Assert.Throws<ConcurrencyException>(() =>
        {
            var saga2 = new SagaData
                {
                    Id = Guid.NewGuid(),
                    UniqueString = uniqueString
                };
            persister.Save(saga2);
            factory.SaveChanges();
        });
    }
    public async Task Should_delete_the_unique_doc_properly()
    {
        var sagaId = Guid.NewGuid();

        IAsyncDocumentSession session;
        var options   = this.CreateContextWithAsyncSessionPresent(out session);
        var persister = new SagaPersister();

        var sagaEntity = new SagaData
        {
            Id     = sagaId,
            SomeId = Guid.NewGuid()
        };
        var synchronizedSession = new RavenDBSynchronizedStorageSession(session);

        await persister.Save(sagaEntity, this.CreateMetadata <SomeSaga>(sagaEntity), synchronizedSession, options);

        //session.Advanced.GetMetadataFor(sagaEntity).Remove("NServiceBus-UniqueDocId");
        await session.SaveChangesAsync().ConfigureAwait(false);

        var saga = await persister.Get <SagaData>(sagaId, synchronizedSession, options);

        await persister.Complete(saga, synchronizedSession, options);

        await session.SaveChangesAsync().ConfigureAwait(false);

        Assert.Null(await session.Query <SagaUniqueIdentity>().Customize(c => c.WaitForNonStaleResults()).SingleOrDefaultAsync(u => u.SagaId == sagaId));
    }
Ejemplo n.º 11
0
    public async Task Inherited_property_classes_should_be_persisted()
    {
        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister = new SagaPersister(new SagaPersistenceConfiguration());
            var entity    = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = "SomeUniqueString",
                PolymorphicRelatedProperty = new PolymorphicProperty
                {
                    SomeInt = 9
                }
            };
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options);

            await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);

            var savedEntity = await persister.Get <SagaData>(entity.Id, synchronizedSession, options);

            var expected = (PolymorphicProperty)entity.PolymorphicRelatedProperty;
            var actual   = (PolymorphicProperty)savedEntity.PolymorphicRelatedProperty;
            Assert.AreEqual(expected.SomeInt, actual.SomeInt);
        }
    }
    public void It_should_enforce_uniqueness()
    {
        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister    = new SagaPersister(factory);
            var uniqueString = Guid.NewGuid().ToString();

            var saga1 = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };

            persister.Save(saga1);
            factory.SaveChanges();
            factory.ReleaseSession();

            Assert.Throws <ConcurrencyException>(() =>
            {
                var saga2 = new SagaData
                {
                    Id           = Guid.NewGuid(),
                    UniqueString = uniqueString
                };
                persister.Save(saga2);
                factory.SaveChanges();
            });
        }
    }
    public async Task It_should_persist_successfully()
    {
        IAsyncDocumentSession session;
        var options      = this.CreateContextWithAsyncSessionPresent(out session);
        var persister    = new SagaPersister();
        var uniqueString = Guid.NewGuid().ToString();

        var saga1 = new SagaData
        {
            Id              = Guid.NewGuid(),
            UniqueString    = uniqueString,
            NonUniqueString = "notUnique"
        };

        var synchronizedSession = new RavenDBSynchronizedStorageSession(session, true);

        await persister.Save(saga1, this.CreateMetadata <SomeSaga>(saga1), synchronizedSession, options);

        await session.SaveChangesAsync().ConfigureAwait(false);

        var saga = await persister.Get <SagaData>(saga1.Id, synchronizedSession, options);

        saga.NonUniqueString = "notUnique2";
        await persister.Update(saga, synchronizedSession, options);

        await session.SaveChangesAsync().ConfigureAwait(false);
    }
    public async Task Public_setters_and_getters_of_concrete_classes_should_be_persisted()
    {
        var entity = new SagaData
        {
            Id            = Guid.NewGuid(),
            UniqueString  = "SomeUniqueString",
            TestComponent = new TestComponent
            {
                Property = "Prop"
            }
        };

        IAsyncDocumentSession session;
        var options             = this.CreateContextWithAsyncSessionPresent(out session);
        var persister           = new SagaPersister();
        var synchronizedSession = new RavenDBSynchronizedStorageSession(session, true);

        await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, options);

        await session.SaveChangesAsync().ConfigureAwait(false);

        var savedEntity = await persister.Get <SagaData>(entity.Id, synchronizedSession, options);

        Assert.AreEqual(entity.TestComponent.Property, savedEntity.TestComponent.Property);
        Assert.AreEqual(entity.TestComponent.AnotherProperty, savedEntity.TestComponent.AnotherProperty);
    }
Ejemplo n.º 15
0
        /// <summary>
        /// Updates a row in the saga data table.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sagaName"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        public Task Update(SagaData data, string sagaName)
        {
            const string UpdateSagaStatement =
                "UPDATE [{0}].[{1}_SagaData] SET" +
                " [Data] = @Data " +
                "WHERE [Id] = @Id";

            if (IsUnsafe(_schemaConfig.Schema))
            {
                throw new ArgumentException(SchemaUnsafe);
            }
            if (IsUnsafe(sagaName))
            {
                throw new ArgumentException(SagaNameUnsafe);
            }
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (string.IsNullOrEmpty(data.Data))
            {
                throw new ArgumentException($"{nameof(data)}.{nameof(data.Data)} must be not null and not empty.");
            }

            var statement = string.Format(UpdateSagaStatement, _schemaConfig.Schema, sagaName);

            var p = new DynamicParameters();

            p.Add("@Id", data.Id);
            p.Add("@Data", data.Data);

            return(_database.Connection.ExecuteAsync(statement, p, _database.Transaction));
        }
    public void It_should_persist_successfully()
    {
        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister           = new SagaPersister(factory);
            var uniqueString        = Guid.NewGuid().ToString();
            var anotherUniqueString = Guid.NewGuid().ToString();

            var saga1 = new SagaData
            {
                Id              = Guid.NewGuid(),
                UniqueString    = uniqueString,
                NonUniqueString = "notUnique"
            };
            persister.Save(saga1);
            factory.SaveChanges();

            var saga = persister.Get <SagaData>(saga1.Id);
            saga.NonUniqueString = "notUnique2";
            saga.UniqueString    = anotherUniqueString;
            persister.Update(saga);
            factory.SaveChanges();
        }
    }
Ejemplo n.º 17
0
    public async Task Inherited_property_classes_should_be_persisted()
    {
        IAsyncDocumentSession session;
        var options   = this.CreateContextWithAsyncSessionPresent(out session);
        var persister = new SagaPersister();
        var entity    = new SagaData
        {
            Id           = Guid.NewGuid(),
            UniqueString = "SomeUniqueString",
            PolymorphicRelatedProperty = new PolymorphicProperty
            {
                SomeInt = 9
            }
        };
        var synchronizedSession = new RavenDBSynchronizedStorageSession(session, true);

        await persister.Save(entity, this.CreateMetadata <SomeSaga>(entity), synchronizedSession, options);

        await session.SaveChangesAsync().ConfigureAwait(false);

        var savedEntity = await persister.Get <SagaData>(entity.Id, synchronizedSession, options);

        var expected = (PolymorphicProperty)entity.PolymorphicRelatedProperty;
        var actual   = (PolymorphicProperty)savedEntity.PolymorphicRelatedProperty;

        Assert.AreEqual(expected.SomeInt, actual.SomeInt);
    }
Ejemplo n.º 18
0
        public async Task CompensationDone <FormType>(SimpleSaga <FormType> saga,
                                                      SagaStep step, string sagaId, SagaData form) where FormType : class, SagaData
        {
            var stepKey = saga.GetSagaDefinition().KeyOfStep(step);

            sagaDoneCompensationSteps.AddOrUpdate(sagaId, new HashSet <string>()
            {
                stepKey
            }, (_, oldSet) => {
                oldSet.Add(stepKey);
                return(oldSet);
            });
            var doneCompensationSteps        = sagaDoneCompensationSteps[sagaId];
            var needDoCompensationStepsCount = saga.GetSagaDefinition().Steps.Count(); // 此sagaId需要执行补偿的steps count

            if (doneCompensationSteps.Count() >= needDoCompensationStepsCount)
            {
                // sagaStates[sagaId] = SagaState.COMPENSATION_DONE;
                var oldInfo = _sagaInfos[sagaId];
                if (oldInfo.State != SagaState.COMPENSATION_DONE)
                {
                    if (!_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_DONE), oldInfo))
                    {
                        throw new SagaAbortException($"saga {sagaId} CompensationDone error because of state update conflict");
                    }
                }
                saga.OnSagaRolledBack(sagaId, form);
            }
            return;
        }
Ejemplo n.º 19
0
    public async Task It_should_persist_successfully()
    {
        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister           = new SagaPersister();
            var uniqueString        = Guid.NewGuid().ToString();
            var anotherUniqueString = Guid.NewGuid().ToString();

            var saga1 = new SagaData
            {
                Id              = Guid.NewGuid(),
                UniqueString    = uniqueString,
                NonUniqueString = "notUnique"
            };

            var synchronizedSession = new RavenDBSynchronizedStorageSession(session);

            await persister.Save(saga1, this.CreateMetadata <SomeSaga>(saga1), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);

            var saga = await persister.Get <SagaData>(saga1.Id, synchronizedSession, options);

            saga.NonUniqueString = "notUnique2";
            saga.UniqueString    = anotherUniqueString;
            await persister.Update(saga, synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);
        }
    }
Ejemplo n.º 20
0
 public async Task CompensationStart <FormType>(SimpleSaga <FormType> saga,
                                                string sagaId, SagaData form) where FormType : class, SagaData
 {
     if (!await SetSagaState(sagaId, SagaState.COMPENSATION_DOING, null))
     {
         throw new SagaAbortException($"sagaId {sagaId} CompensationStart error because of set state conflict");
     }
 }
Ejemplo n.º 21
0
        public void TestInitialize()
        {
            dataAccess   = new Mock <IBusDataAccess>();
            log          = new Mock <ILog <QueueReader> >();
            perfCounters = new Mock <IPerfCounters>();
            serializer   = new Mock <ISerializer>();
            clock        = new Mock <ISystemClock>();

            clock.SetupGet(x => x.UtcNow)
            .Returns(new DateTime(2022, 2, 22, 14, 22, 22, 222, DateTimeKind.Utc));

            dataAccess.Setup(d => d.Update(It.IsAny <QueueMessage>(), It.IsAny <string>()))
            .Callback <QueueMessage, string>((m, q) =>
            {
                UpdatedMessage = m;
                UpdatedQueue   = q;
            })
            .Returns(Task.CompletedTask);

            dataAccess.Setup(d => d.Insert(It.IsAny <SagaData>(), It.IsAny <string>()))
            .Callback <SagaData, string>((d, n) =>
            {
                InsertedSagaData = d;
                InsertedSagaName = n;
            })
            .Returns(Task.FromResult <long>(12345));

            dataAccess.Setup(d => d.Update(It.IsAny <SagaData>(), It.IsAny <string>()))
            .Callback <SagaData, string>((d, n) =>
            {
                UpdatedSagaData = d;
                UpdatedSagaName = n;
            })
            .Returns(Task.CompletedTask);

            dataAccess.Setup(d => d.FailMessage(It.IsAny <QueueMessage>(), It.IsAny <string>()))
            .Callback <QueueMessage, string>((d, n) =>
            {
                FailedMessage = d;
                FailedQueue   = n;
            })
            .Returns(Task.CompletedTask);

            dataAccess.Setup(d => d.CompleteMessage(It.IsAny <QueueMessage>(), It.IsAny <string>()))
            .Callback <QueueMessage, string>((d, n) =>
            {
                CompletedMessage = d;
                CompletedQueue   = n;
            })
            .Returns(Task.CompletedTask);

            serializer.Setup(s => s.SerializeSaga(It.IsAny <object>(), typeof(TestSagaData)))
            .Returns("SerializedTestSagaData");

            reader = new QueueReader(dataAccess.Object, log.Object, perfCounters.Object, serializer.Object, clock.Object);
        }
Ejemplo n.º 22
0
        public async Task <SagaData> GetSagaData(string sagaId)
        {
            SagaData sagaData = null;

            if (!_sagaDatas.TryGetValue(sagaId, out sagaData))
            {
                return(null);
            }
            return(sagaData);
        }
Ejemplo n.º 23
0
        protected int SINGLE_STEP_COMPENSATION_TRY_COUNT = 3; // 一个步骤的补偿任务最多重试的次数

        public Task CompensationException <FormType>(SimpleSaga <FormType> saga,
                                                     SagaStep step, string sagaId, SagaData form, Exception e) where FormType : class, SagaData
        {
            // 记录失败信息和失败次数
            var key = makeSagaIdAndStepKey(sagaId, saga, step);

            sagaStepsCompensationFailCount.AddOrUpdate(key, 1, (_, oldCount) => oldCount + 1);
            var failCount = sagaStepsCompensationFailCount[key];

            if (failCount >= SINGLE_STEP_COMPENSATION_TRY_COUNT)
            {
                // 这个step的补偿任务执行失败次数太多了
                Console.WriteLine($"saga {sagaId} step {saga.GetSagaDefinition().KeyOfStep(step)} compensation fail too many times error {e.Message}");
                // sagaStates.TryUpdate(sagaId, SagaState.COMPENSATION_FAIL, SagaState.COMPENSATION_DOING);
                while (true)
                {
                    if (!_sagaInfos.ContainsKey(sagaId))
                    {
                        break;
                    }
                    var oldInfo = _sagaInfos[sagaId];
                    if (oldInfo.State.IsEndState())
                    {
                        break;
                    }
                    if (_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_FAIL), oldInfo))
                    {
                        break;
                    }
                }
            }
            else
            {
                while (true)
                {
                    if (!_sagaInfos.ContainsKey(sagaId))
                    {
                        break;
                    }
                    var oldInfo = _sagaInfos[sagaId];
                    if (oldInfo.State.IsEndState() || oldInfo.State == SagaState.COMPENSATION_ERROR)
                    {
                        break;
                    }
                    if (_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(SagaState.COMPENSATION_ERROR), oldInfo))
                    {
                        break;
                    }
                }
            }
            return(Task.CompletedTask);
        }
Ejemplo n.º 24
0
        private async Task ProcessAsync <TMessage>(Guid?nid, Type sagaType, Type sagaDataType, TMessage message, ISagaAction <TMessage> action, ISagaContext context = null) where TMessage : class
        {
            context = context ?? SagaContext.Empty;

            var saga     = (ISaga)action;
            var id       = nid ?? saga.ResolveId(message, context);
            var sagaData = await _repository.ReadAsync(id, sagaType).ConfigureAwait(false);

            if (sagaData is null)
            {
                if (!(action is ISagaStartAction <TMessage>))
                {
                    return;
                }
                sagaData = SagaData.Create(id, sagaType, SagaStates.Pending, Activator.CreateInstance(sagaDataType));
            }
            else if (sagaData.State == SagaStates.Rejected)
            {
                return;
            }

            saga.Initialize(sagaData.SagaId, sagaData.State, sagaData.Data);

            var isError = false;

            try
            {
                await action.HandleAsync(message, context);
            }
            catch
            {
                isError = true;
            }

            var newSagaData = SagaData.Create(id, sagaType, saga.State, saga.Data);
            var sagaLogData = SagaLogData.Create(id, sagaType, message);

            var persistanceTasks = new Task[2]
            {
                _repository.WriteAsync(newSagaData),
                _sagaLog.SaveAsync(sagaLogData)
            };

            await Task.WhenAll(persistanceTasks).ConfigureAwait(false);

            if (saga.State is SagaStates.Rejected || isError)
            {
                await CompensateAsync(saga, sagaType, context);
            }
        }
Ejemplo n.º 25
0
        public async Task <string> ProcessSomeUnfinishedSagasAsync(int limit, string lastProcessSagaId)
        {
            var sagaIds = await sagaStore.ListSagaIdsInStates(new List <SagaState>(){
                SagaState.PROCESSING, SagaState.COMPENSATION_DOING, SagaState.COMPENSATION_ERROR
            }, limit, lastProcessSagaId);

            _logger.LogInformation($"there are {sagaIds.Count} unfinished sagaIds to process");
            if (sagaIds.Count < 1)
            {
                return(null);
            }
            foreach (var sagaId in sagaIds)
            {
                try
                {
                    var sagaInfo = await sagaStore.GetSagaInfo(sagaId);

                    if (sagaInfo.State == SagaState.PROCESSING)
                    {
                        // 如果是正常处理中的sagaId,如果没有超时,则不做补偿等后续操作
                        if (!sagaInfo.IsExpired())
                        {
                            continue;
                        }
                    }
                    try
                    {
                        if (!await sagaStore.LockSagaProcess(sagaId, _workerId, TimeSpan.FromSeconds(60)))
                        {
                            throw new SagaProcessException($"worker {_workerId} lock saga {sagaId} to process error");
                        }
                        _logger.LogInformation($"worker {_workerId} start process saga {sagaId}");
                        SagaData sagaData = await sagaStore.GetSagaData(sagaId);
                        await ProcessUnfinishedSagaAsync(sagaId, sagaData);

                        _logger.LogInformation($"worker {_workerId} process saga {sagaId} done");
                    }
                    finally
                    {
                        await sagaStore.UnlockSagaProcess(sagaId, _workerId);
                    }
                }
                catch (Exception e)
                {
                    _logger.LogError($"process unifinished saga {sagaId} error {e.Message}");
                }
            }
            return(sagaIds[sagaIds.Count - 1]);
        }
Ejemplo n.º 26
0
    public async Task It_should_persist_successfully()
    {
        var saga1Id      = Guid.NewGuid();
        var uniqueString = Guid.NewGuid().ToString();

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister = new SagaPersister(new SagaPersistenceConfiguration());
            var saga1     = new SagaData
            {
                Id           = saga1Id,
                UniqueString = uniqueString
            };

            var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options);

            await persister.Save(saga1, this.CreateMetadata <SomeSaga>(saga1), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);
        }

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister           = new SagaPersister(new SagaPersistenceConfiguration());
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options);

            var saga = await persister.Get <SagaData>(saga1Id, synchronizedSession, options);

            await persister.Complete(saga, synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);
        }

        using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options))
        {
            var persister           = new SagaPersister(new SagaPersistenceConfiguration());
            var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options);

            var saga2 = new SagaData
            {
                Id           = Guid.NewGuid(),
                UniqueString = uniqueString
            };

            await persister.Save(saga2, this.CreateMetadata <SomeSaga>(saga2), synchronizedSession, options);

            await session.SaveChangesAsync().ConfigureAwait(false);
        }
    }
        async Task SimulateProcessingMessage(SagaData sagaData, Action <SagaData> action, bool commitOutboxTransaction, ContextBag context)
        {
            var outboxTransaction = await outboxPersister.BeginTransaction(context);

            var session = new OutboxEventStoreSynchronizedStorageSession(connection, (EventStoreOutboxTransaction)outboxTransaction);

            sagaData = await persister.Get <SagaData>(CorrelationPropName, sagaData.StringProperty, session, context);

            action(sagaData);
            await persister.Update(sagaData, session, context);

            if (commitOutboxTransaction)
            {
                await outboxTransaction.Commit();
            }
        }
Ejemplo n.º 28
0
        public async Task ProcessUnfinishedSagaAsync(string sagaId, SagaData sagaData)
        {
            var sagaInfo = await sagaStore.GetSagaInfo(sagaId);

            if (sagaInfo == null)
            {
                return;
            }
            if (sagaInfo.State.IsEndState())
            {
                return;
            }
            var sagaDefinition = sagaInfo.Definition;
            var saga           = sagaDefinition.Saga;
            await saga.DoCompensationOfSaga(sagaId, sagaData);
        }
    public void Enums_should_be_persisted()
    {
        var entity = new SagaData
            {
                Id = Guid.NewGuid(),
                Status = StatusEnum.AnotherStatus
            };

        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        persister.Save(entity);
        factory.SaveChanges();

        var savedEntity = persister.Get<SagaData>(entity.Id);
        Assert.AreEqual(entity.Status, savedEntity.Status);
    }
Ejemplo n.º 30
0
        /// <summary>
        /// Inserts a row into a saga data table.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sagaName"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentNullException"></exception>
        public Task <long> Insert(SagaData data, string sagaName)
        {
            const string InsertSagaStatement =
                "INSERT INTO[{0}].[{1}_SagaData]" +
                " ([SagaId], [Key], [Data]) " +
                "VALUES" +
                " (@SagaId, @Key, @Data); " +
                "SELECT SCOPE_IDENTITY()";

            if (IsUnsafe(_schemaConfig.Schema))
            {
                throw new ArgumentException(SchemaUnsafe);
            }
            if (IsUnsafe(sagaName))
            {
                throw new ArgumentException(SagaNameUnsafe);
            }
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (data.SagaId == null)
            {
                throw new ArgumentNullException($"{nameof(data)}.{nameof(data.SagaId)}");
            }
            if (string.IsNullOrEmpty(data.Key))
            {
                throw new ArgumentException($"{nameof(data)}.{nameof(data.Key)} must be not null and not empty.");
            }
            if (string.IsNullOrEmpty(data.Data))
            {
                throw new ArgumentException($"{nameof(data)}.{nameof(data.Data)} must be not null and not empty.");
            }

            string statement = string.Format(InsertSagaStatement, _schemaConfig.Schema, sagaName);

            var p = new DynamicParameters();

            p.Add("@SagaId", data.SagaId);
            p.Add("@Key", data.Key);
            p.Add("@Data", data.Data);

            return(_database.Connection.QueryFirstAsync <long>(statement, p, _database.Transaction));
        }
    public void Datetime_property_should_be_persisted()
    {
        var entity = new SagaData
        {
            Id = Guid.NewGuid(),
            DateTimeProperty = DateTime.Parse("12/02/2010 12:00:00.01")
        };

        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister = new SagaPersister(factory);
            persister.Save(entity);
            factory.SaveChanges();
            var savedEntity = persister.Get <SagaData>(entity.Id);
            Assert.AreEqual(entity.DateTimeProperty, savedEntity.DateTimeProperty);
        }
    }
 public void Public_setters_and_getters_of_concrete_classes_should_be_persisted()
 {
     var entity = new SagaData
             {
                 Id = Guid.NewGuid(),
                 TestComponent = new TestComponent
                     {
                         Property = "Prop"
                     }
             };
     var factory = new RavenSessionFactory(store);
     factory.ReleaseSession();
     var persister = new SagaPersister(factory);
     persister.Save(entity);
     factory.SaveChanges();
     var savedEntity = persister.Get<SagaData>(entity.Id);
     Assert.AreEqual(entity.TestComponent.Property, savedEntity.TestComponent.Property);
     Assert.AreEqual(entity.TestComponent.AnotherProperty, savedEntity.TestComponent.AnotherProperty);
 }
Ejemplo n.º 33
0
    public void It_should_set_the_attribute_and_allow_the_update()
    {
        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister    = new SagaPersister(factory);
            var uniqueString = Guid.NewGuid().ToString();

            var anotherUniqueString = Guid.NewGuid().ToString();

            var saga1 = new SagaData
            {
                Id              = Guid.NewGuid(),
                UniqueString    = uniqueString,
                NonUniqueString = "notUnique"
            };

            persister.Save(saga1);
            factory.SaveChanges();
            factory.ReleaseSession();

            using (var session = store.OpenSession())
            {
                //fake that the attribute was just added by removing the metadata
                session.Advanced.GetMetadataFor(saga1).Remove(SagaPersister.UniqueValueMetadataKey);
                session.SaveChanges();
            }

            var saga = persister.Get <SagaData>(saga1.Id);
            saga.UniqueString = anotherUniqueString;
            persister.Update(saga);
            factory.SaveChanges();
            factory.ReleaseSession();

            using (var session = store.OpenSession())
            {
                var value = session.Advanced.GetMetadataFor(saga1)[SagaPersister.UniqueValueMetadataKey].ToString();
                Assert.AreEqual(anotherUniqueString, value);
            }
        }
    }
    public void Enums_should_be_persisted()
    {
        var entity = new SagaData
        {
            Id     = Guid.NewGuid(),
            Status = StatusEnum.AnotherStatus
        };

        using (var store = DocumentStoreBuilder.Build())
        {
            var factory = new RavenSessionFactory(store);
            factory.ReleaseSession();
            var persister = new SagaPersister(factory);
            persister.Save(entity);
            factory.SaveChanges();

            var savedEntity = persister.Get <SagaData>(entity.Id);
            Assert.AreEqual(entity.Status, savedEntity.Status);
        }
    }
    public async Task should_throw_a_ArgumentNullException()
    {
        var saga1 = new SagaData
        {
            Id           = Guid.NewGuid(),
            UniqueString = null
        };

        IAsyncDocumentSession session;
        var context      = this.CreateContextWithAsyncSessionPresent(out session);
        var ravenSession = new RavenDBSynchronizedStorageSession(session, true);
        var persister    = new SagaPersister();

        var exception = await Catch <ArgumentNullException>(async() =>
        {
            await persister.Save(saga1, this.CreateMetadata <SomeSaga>(saga1), ravenSession, context);
            await session.SaveChangesAsync().ConfigureAwait(false);
        });

        Assert.IsNotNull(exception);
    }
    public void Inherited_property_classes_should_be_persisted()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var entity = new SagaData
            {
                Id = Guid.NewGuid(),
                PolymorphicRelatedProperty = new PolymorphicProperty
                    {
                        SomeInt = 9
                    }
            };
        persister.Save(entity);
        factory.SaveChanges();

        var savedEntity = persister.Get<SagaData>(entity.Id);
        var expected = (PolymorphicProperty)entity.PolymorphicRelatedProperty;
        var actual = (PolymorphicProperty)savedEntity.PolymorphicRelatedProperty;
        Assert.AreEqual(expected.SomeInt, actual.SomeInt);
    }
    public void It_should_set_the_attribute_and_allow_the_update()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var uniqueString = Guid.NewGuid().ToString();

        var anotherUniqueString = Guid.NewGuid().ToString();

        var saga1 = new SagaData
            {
                Id = Guid.NewGuid(),
                UniqueString = uniqueString,
                NonUniqueString = "notUnique"
            };

        persister.Save(saga1);
        factory.SaveChanges();
        factory.ReleaseSession();

        using (var session = store.OpenSession())
        {
            //fake that the attribute was just added by removing the metadata
            session.Advanced.GetMetadataFor(saga1).Remove(SagaPersister.UniqueValueMetadataKey);
            session.SaveChanges();
        }

        var saga = persister.Get<SagaData>(saga1.Id);
        saga.UniqueString = anotherUniqueString;
        persister.Update(saga);
        factory.SaveChanges();
        factory.ReleaseSession();

        using (var session = store.OpenSession())
        {
            var value = session.Advanced.GetMetadataFor(saga1)[SagaPersister.UniqueValueMetadataKey].ToString();
            Assert.AreEqual(anotherUniqueString, value);
        }
    }
    public void It_should_persist_successfully()
    {
        var factory = new RavenSessionFactory(store);
        factory.ReleaseSession();
        var persister = new SagaPersister(factory);
        var uniqueString = Guid.NewGuid().ToString();
        var anotherUniqueString = Guid.NewGuid().ToString();

        var saga1 = new SagaData
        {
            Id = Guid.NewGuid(),
            UniqueString = uniqueString,
            NonUniqueString = "notUnique"
        };
        persister.Save(saga1);
        factory.SaveChanges();

        var saga = persister.Get<SagaData>(saga1.Id);
        saga.NonUniqueString = "notUnique2";
        saga.UniqueString = anotherUniqueString;
        persister.Update(saga);
        factory.SaveChanges();
    }
Ejemplo n.º 39
0
 public SagaHeader(SagaData data)
 {
     this.data = data;
 }
Ejemplo n.º 40
0
 public SagaFooter(SagaData data)
 {
     this.data = data;
 }