예제 #1
0
        private async Task ProcessAsync <TMessage>(TMessage message, ISagaAction <TMessage> action,
                                                   Func <TMessage, ISagaContext, Task> onCompleted, Func <TMessage, ISagaContext, Task> onRejected,
                                                   ISagaContext context = null) where TMessage : class
        {
            context = context ?? SagaContext.Empty;
            var saga     = (ISaga)action;
            var sagaType = saga.GetType();
            var id       = saga.ResolveId(message, context);
            var dataType = saga.GetSagaDataType();

            await Semaphore.WaitAsync();

            try
            {
                var state = await _repository.ReadAsync(id, sagaType).ConfigureAwait(false);

                if (state is null)
                {
                    if (!(action is ISagaStartAction <TMessage>))
                    {
                        return;
                    }

                    state = CreateSagaState(id, sagaType, dataType);
                }
                else if (state.State == SagaStates.Rejected)
                {
                    return;
                }

                InitializeSaga(saga, id, state);

                try
                {
                    await action.HandleAsync(message, context);
                }
                catch (Exception e)
                {
                    context.SagaContextError = new SagaContextError(e);
                    saga.Reject();
                }

                await UpdateSagaAsync(message, saga, state);
            }
            finally
            {
                Semaphore.Release();
            }

            if (saga.State is SagaStates.Rejected)
            {
                await onRejected(message, context);
                await CompensateAsync(saga, sagaType, context);
            }
            else if (saga.State is SagaStates.Completed)
            {
                await onCompleted(message, context);
            }
        }
예제 #2
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);
            }
        }