Пример #1
0
        public static async Task SagaOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            TransactionItem item = context.GetInput <TransactionItem>();

            var commandProducers = new Dictionary <string, Func <Task <ActivityResult <ProducerResult> > > >
            {
                [nameof(ValidateTransferCommand)] = () => ActivityFactory.ProduceValidateTransferCommandAsync(item, context, log),
                [nameof(TransferCommand)]         = () => ActivityFactory.ProduceTransferCommandAsync(item, context, log),
                [nameof(CancelTransferCommand)]   = () => ActivityFactory.ProduceCancelTransferCommandAsync(item, context, log),
                [nameof(IssueReceiptCommand)]     = () => ActivityFactory.ProduceIssueReceiptCommandAsync(item, context, log)
            };

            var sagaStatePersisters = new Dictionary <string, Func <Task <bool> > >
            {
                [nameof(SagaState.Pending)]   = () => SagaFactory.PersistSagaStateAsync(item, SagaState.Pending, context, log),
                [nameof(SagaState.Success)]   = () => SagaFactory.PersistSagaStateAsync(item, SagaState.Success, context, log),
                [nameof(SagaState.Cancelled)] = () => SagaFactory.PersistSagaStateAsync(item, SagaState.Cancelled, context, log),
                [nameof(SagaState.Fail)]      = () => SagaFactory.PersistSagaStateAsync(item, SagaState.Fail, context, log),
            };

            try
            {
                var       orchestrator = new DurableOrchestrator(commandProducers, sagaStatePersisters);
                SagaState sagaState    = await orchestrator.OrchestrateAsync(item, context, log);

                log.LogInformation($@"Saga state = {nameof(sagaState)} [{context.InstanceId}]");
            }
            catch (ArgumentException ex)
            {
                log.LogError(ex.Message);
            }
        }
Пример #2
0
        }                                               // sagaId的定义



        public SagaInfo SetStateClone(SagaState newState)
        {
            var c = this.Clone();

            c.State = newState;
            return(c);
        }
Пример #3
0
 public SagaState ToSagaState()
 {
     var type = Type.GetType(StateType);
     var state = ContractlessMessagePackSerializer.Instance.BinaryDeSerialize(SagaState, type);
     var sagaState = new SagaState(Id, state);
     sagaState.SagaVersion = SagaVersion;
     return sagaState;
 }
Пример #4
0
        public async Task Update(Guid correlationId, object state)
        {
            var table = await _tableService.GetTable(EVENT_STORE_TABLE_NAME, false).ConfigureAwait(false);

            var entity          = new SagaState(correlationId, state);
            var insertOperation = TableOperation.InsertOrReplace(entity);
            await table.ExecuteAsync(insertOperation).ConfigureAwait(false);
        }
Пример #5
0
 public Task HandleAsync(
     IDomainEvent <SagaTestAggregate, SagaTestAggregateId, SagaTestEventA> domainEvent,
     ISagaContext sagaContext,
     CancellationToken cancellationToken)
 {
     Publish(new SagaTestBCommand(domainEvent.AggregateIdentity));
     State = SagaState.Running;
     return(Task.FromResult(0));
 }
Пример #6
0
 private static TransactionItem CreateValidTransactionItem(SagaState state)
 {
     return(new TransactionItem
     {
         Id = Guid.NewGuid().ToString(),
         AccountFromId = Guid.NewGuid().ToString(),
         AccountToId = Guid.NewGuid().ToString(),
         Amount = 100.00M,
         State = nameof(state)
     });
 }
Пример #7
0
        public async Task Saga_should_succeed_with_successful_compensation_workflow()
        {
            var transactionItem = CreateFakeTransactionItem();

            var commandProducers = new Dictionary <string, Func <Task <ActivityResult <ProducerResult> > > >
            {
                [nameof(ValidateTransferCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                }),
                [nameof(TransferCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                }),
                [nameof(CancelTransferCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                }),
                [nameof(IssueReceiptCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                })
            };

            var sagaStatePersisters = new Dictionary <string, Func <Task <bool> > >
            {
                [nameof(SagaState.Pending)]   = () => Task.Run(() => true),
                [nameof(SagaState.Success)]   = () => Task.Run(() => true),
                [nameof(SagaState.Cancelled)] = () => Task.Run(() => true),
            };

            var loggerMock  = new Mock <ILogger>();
            var mockContext = new Mock <IDurableOrchestrationContext>();

            mockContext
            .Setup(x => x.WaitForExternalEvent <string>(nameof(Sources.Validator)))
            .ReturnsAsync(nameof(TransferValidatedEvent));

            mockContext
            .SetupSequence(x => x.WaitForExternalEvent <string>(nameof(Sources.Transfer)))
            .ReturnsAsync(nameof(TransferSucceededEvent))
            .ReturnsAsync(nameof(TransferCanceledEvent));

            mockContext
            .Setup(x => x.WaitForExternalEvent <string>(nameof(Sources.Receipt)))
            .ReturnsAsync(nameof(OtherReasonReceiptFailedEvent));

            var       orchestrator = new DurableOrchestrator(commandProducers, sagaStatePersisters);
            SagaState sagaState    = await orchestrator.OrchestrateAsync(transactionItem, mockContext.Object, loggerMock.Object);

            Assert.Equal(SagaState.Cancelled, sagaState);
        }
Пример #8
0
        public static async Task <bool> PersistSagaStateAsync(
            TransactionItem transactionItem, SagaState state, IDurableOrchestrationContext context, ILogger log)
        {
            TransactionItem item = TransactionFactory.BuildTransactionItemByState(transactionItem, state);
            ActivityResult <TransactionItem> result = await PersistSagaStateAsync(context, item);

            if (!result.Valid)
            {
                log.LogError(result.ExceptionMessage);
                return(false);
            }

            return(true);
        }
Пример #9
0
        public async Task <bool> SetSagaState(string sagaId, SagaState state, SagaState?oldState)
        {
            if (oldState == null)
            {
                _sagaInfos[sagaId] = _sagaInfos[sagaId].SetStateClone(state);
                return(true);
            }
            if (!_sagaInfos.ContainsKey(sagaId))
            {
                return(true);
            }
            var oldInfo = _sagaInfos[sagaId];

            return(_sagaInfos.TryUpdate(sagaId, oldInfo.SetStateClone(state), oldInfo));
        }
Пример #10
0
        private async Task UpdateState(
            SagaState sagaState,
            State initialState,
            State newState,
            SagaAction sagaActions)
        {
            sagaState.ExtendedData = JsonConvert.SerializeObject(newState.Value);
            await stateDAO.Update(sagaState);

            var sagaLog = new SagaStateLog
            {
                InitialState = JsonConvert.SerializeObject(initialState.Value),
                FinshedState = JsonConvert.SerializeObject(newState.Value),
                SagaId       = sagaState.SagaInfoId,
                ActionId     = sagaActions.Id
            };

            await actionLogStateDAO.Save(sagaLog);
        }
Пример #11
0
        private Mock <ISaga> Arrange_Woking_SagaStore(SagaState sagaState = SagaState.New)
        {
            var sagaMock = new Mock <ISaga>();

            sagaMock
            .Setup(s => s.State)
            .Returns(sagaState);

            _sagaStoreMock
            .Setup(s => s.UpdateAsync(
                       It.IsAny <ISagaId>(),
                       It.IsAny <Type>(),
                       It.IsAny <ISourceId>(),
                       It.IsAny <Func <ISaga, CancellationToken, Task> >(),
                       It.IsAny <CancellationToken>()))
            .Callback <ISagaId, Type, ISourceId, Func <ISaga, CancellationToken, Task>, CancellationToken>(
                (id, details, arg3, arg4, arg5) => arg4(sagaMock.Object, CancellationToken.None))
            .ReturnsAsync(sagaMock.Object);

            return(sagaMock);
        }
Пример #12
0
        public async Task Saga_should_not_be_orchestrated_with_invalid_events()
        {
            var transactionItem = CreateFakeTransactionItem();

            var commandProducers = new Dictionary <string, Func <Task <ActivityResult <ProducerResult> > > >
            {
                [nameof(ValidateTransferCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                }),
                [nameof(TransferCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                }),
                [nameof(IssueReceiptCommand)] = () => Task.Run(() => new ActivityResult <ProducerResult>
                {
                    Item = new ProducerResult()
                })
            };

            var sagaStatePersisters = new Dictionary <string, Func <Task <bool> > >
            {
                [nameof(SagaState.Pending)] = () => Task.Run(() => true),
                [nameof(SagaState.Success)] = () => Task.Run(() => true),
                [nameof(SagaState.Fail)]    = () => Task.Run(() => true),
            };

            var loggerMock  = new Mock <ILogger>();
            var mockContext = new Mock <IDurableOrchestrationContext>();

            mockContext
            .Setup(x => x.WaitForExternalEvent <string>(nameof(Sources.Validator)))
            .ReturnsAsync(nameof(ReceiptIssuedEvent));

            var       orchestrator = new DurableOrchestrator(commandProducers, sagaStatePersisters);
            SagaState sagaState    = await orchestrator.OrchestrateAsync(transactionItem, mockContext.Object, loggerMock.Object);

            Assert.Equal(SagaState.Fail, sagaState);
        }
Пример #13
0
 public TestSaga(TestSagaId id)
 {
     Id    = id;
     State = SagaState.New;
 }
Пример #14
0
 public void Reject()
 => State = SagaState.Rejected;
Пример #15
0
 public void Complete()
 => State = SagaState.Completed;
Пример #16
0
 public void Initialize()
 {
     SagaId = Guid.NewGuid().ToString();
     State  = SagaState.Pending;
 }
Пример #17
0
        private static ISagaState CreateSagaState(SagaId id, Type sagaType, Type dataType)
        {
            var sagaData = dataType != null?Activator.CreateInstance(dataType) : null;

            return(SagaState.Create(id, sagaType, SagaStates.Pending, sagaData));
        }
Пример #18
0
 public static bool IsEndState(this SagaState state)
 {
     return(state == SagaState.SUCCESS || state == SagaState.COMPENSATION_DONE || state == SagaState.COMPENSATION_FAIL);
 }
Пример #19
0
 internal async Task Update(SagaState sagaState)
 {
     using var context = _serviceProvider.GetRequiredService <SagaContext>();
     context.States.Update(sagaState);
     await context.SaveChangesAsync();
 }
 public static TransactionItem BuildTransactionItemByState(TransactionItem item, SagaState state)
 {
     return(new TransactionItem
     {
         Id = item.Id,
         AccountFromId = item.AccountFromId,
         AccountToId = item.AccountToId,
         Amount = item.Amount,
         State = state.ToString()
     });
 }
Пример #21
0
 public Task <bool> SetSagaState(string sagaId, SagaState state, SagaState?oldState)
 {
     return(Task.FromResult(true));
 }