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); } }
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); } }