Ejemplo n.º 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);
            }
        }
Ejemplo n.º 2
0
        public async Task Saga_should_fail_with_invalid_external_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.Fail)] = () => Task.Run(() => true)
            };

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

            var orchestrator = new DurableOrchestrator(commandProducers, sagaStatePersisters);
            await Assert.ThrowsAsync <KeyNotFoundException>(() => orchestrator.OrchestrateAsync(transactionItem, mockContext.Object, loggerMock.Object));
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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);
        }