public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { if (_log.IsDebugEnabled) { _log.DebugFormat("SAGA:{0}:{1} Added {2}", TypeMetadataCache <TSaga> .ShortName, context.Saga.CorrelationId, TypeMetadataCache <TMessage> .ShortName); } SagaConsumeContext <TSaga, TMessage> proxy = new RedLockSagaConsumeContext <TSaga, TMessage>(_redisDb, _lockFactory, context, context.Saga, _redisPrefix); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { using (var distLock = _lockFactory.Create($"redislock:{context.Saga.CorrelationId}", _expiry, _wait, _retryTime)) { if (distLock.IsAcquired) { // Work inside Lock await _redisDb.As <TSaga>().Put(context.Saga.CorrelationId, context.Saga, _redisPrefix).ConfigureAwait(false); } } } }
public static void LogFault <TSaga, TMessage>(this SagaConsumeContext <TSaga, TMessage> context, Exception exception, Guid?correlationId = default) where TSaga : class, ISaga where TMessage : class { LogContext.Error?.Log(exception, "SAGA:{SagaType}:{CorrelationId} Fault {MessageType}", TypeMetadataCache <TSaga> .ShortName, correlationId, TypeMetadataCache <TMessage> .ShortName); }
public async Task Send(SagaConsumeContext <TInstance, TData> context, IPipe <SagaConsumeContext <TInstance, TData> > next) { var eventContext = new StateMachineEventContextProxy <TInstance, TData>(context, _machine, context.Saga, _event, context.Message); var activity = LogContext.IfEnabled(OperationName.Saga.RaiseEvent) ?.StartSagaActivity(context, (await _machine.Accessor.Get(eventContext).ConfigureAwait(false)).Name); try { await _machine.RaiseEvent(eventContext).ConfigureAwait(false); if (await _machine.IsCompleted(context.Saga).ConfigureAwait(false)) { await context.SetCompleted().ConfigureAwait(false); } } catch (UnhandledEventException ex) { var currentState = await _machine.Accessor.Get(eventContext).ConfigureAwait(false); throw new NotAcceptedStateMachineException(typeof(TInstance), typeof(TData), context.CorrelationId ?? Guid.Empty, currentState.Name, ex); } finally { activity?.AddTag(DiagnosticHeaders.EndState, (await _machine.Accessor.Get(eventContext).ConfigureAwait(false)).Name); activity?.Stop(); } }
public Task Send(ConsumeContext <TMessage> context) { SagaConsumeContext <TSaga, TMessage> sagaContext = context as SagaConsumeContext <TSaga, TMessage> ?? new SagaConsumeContextProxy <TSaga, TMessage>(context, _context); return(_output.Send(sagaContext)); }
public static void LogUsed <TSaga, TMessage>(this SagaConsumeContext <TSaga, TMessage> context, Guid?correlationId = default) where TSaga : class, ISaga where TMessage : class { LogContext.Debug?.Log("SAGA:{SagaType}:{CorrelationId} Used {MessageType}", TypeMetadataCache <TSaga> .ShortName, context.CorrelationId ?? correlationId, TypeMetadataCache <TMessage> .ShortName); }
public async Task Send(SagaConsumeContext <TInstance, TData> context, IPipe <SagaConsumeContext <TInstance, TData> > next) { var eventContext = new StateMachineEventContext <TInstance, TData>(_machine, context.Saga, _event, context.Message, context.CancellationToken); eventContext.GetOrAddPayload(() => context); eventContext.GetOrAddPayload(() => (ConsumeContext <TData>)context); eventContext.GetOrAddPayload(() => (ConsumeContext)context); State <TInstance> currentState = await _machine.Accessor.Get(eventContext).ConfigureAwait(false); IEnumerable <Event> nextEvents = _machine.NextEvents(currentState); if (nextEvents.Contains(_event)) { await _machine.RaiseEvent(eventContext).ConfigureAwait(false); if (_machine.IsCompleted(context.Saga)) { await context.SetCompleted().ConfigureAwait(false); } } else { throw new NotAcceptedStateMachineException(typeof(TInstance), typeof(TData), context.CorrelationId ?? Guid.Empty, currentState.Name); } }
async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance) where T : class { try { SagaConsumeContext <TSaga, T> sagaConsumeContext = _documentDbSagaConsumeContextFactory.Create(_client, _databaseName, _collectionName, context, instance, true, _requestOptions); sagaConsumeContext.LogUsed(); await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false); if (!sagaConsumeContext.IsCompleted) { await UpdateDocumentDbSaga(context, instance).ConfigureAwait(false); } } catch (SagaException) { throw; } catch (Exception ex) { throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex); } }
public void GivenAMongoDbSagaConsumeContext_WhenPoppingContext() { var mongoDbSagaConsumeContext = new MongoDbSagaConsumeContext <SimpleSaga, InitiateSimpleSaga>(Mock.Of <IMongoCollection <SimpleSaga> >(), Mock.Of <ConsumeContext <InitiateSimpleSaga> >(), Mock.Of <SimpleSaga>()); _context = mongoDbSagaConsumeContext.PopContext <InitiateSimpleSaga>(); }
async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance) where T : class { try { SagaConsumeContext <TSaga, T> sagaConsumeContext = _mongoDbSagaConsumeContextFactory.Create(_collection, context, instance); sagaConsumeContext.LogUsed(); await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false); if (!sagaConsumeContext.IsCompleted) { await UpdateMongoDbSaga(context, instance).ConfigureAwait(false); } } catch (SagaException sex) { context.LogFault(this, sex, instance?.CorrelationId); throw; } catch (Exception ex) { throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex); } }
public void GivenADocumentDbSagaConsumeContext_WhenPoppingContext() { var mongoDbSagaConsumeContext = new DocumentDbSagaConsumeContext <SimpleSaga, InitiateSimpleSaga>(It.IsAny <IDocumentClient>(), It.IsAny <string>(), It.IsAny <string>(), Mock.Of <ConsumeContext <InitiateSimpleSaga> >(), Mock.Of <SimpleSaga>()); _context = mongoDbSagaConsumeContext.PopContext <InitiateSimpleSaga>(); }
public async Task Send(SagaRepositoryQueryContext <TSaga, T> context) { if (context.Count > 0) { async Task LoadInstance(Guid correlationId) { SagaConsumeContext <TSaga, T> sagaConsumeContext = await context.Load(correlationId).ConfigureAwait(false); if (sagaConsumeContext != null) { sagaConsumeContext.LogUsed(); try { await _policy.Existing(sagaConsumeContext, _next).ConfigureAwait(false); if (_policy.IsReadOnly) { await context.Undo(sagaConsumeContext).ConfigureAwait(false); } else { if (sagaConsumeContext.IsCompleted) { await context.Delete(sagaConsumeContext).ConfigureAwait(false); sagaConsumeContext.LogRemoved(); } else { await context.Update(sagaConsumeContext).ConfigureAwait(false); } } } finally { switch (sagaConsumeContext) { case IAsyncDisposable asyncDisposable: await asyncDisposable.DisposeAsync().ConfigureAwait(false); break; case IDisposable disposable: disposable.Dispose(); break; } } } } await Task.WhenAll(context.Select(LoadInstance)).ConfigureAwait(false); } else { var missingPipe = new MissingSagaPipe <TSaga, T>(context, _next); await _policy.Missing(context, missingPipe).ConfigureAwait(false); } }
public void GivenAMongoDbSagaConsumeContext_WhenPoppingContext() { var mongoDbSagaConsumeContext = new MongoDbSagaConsumeContext<SimpleSaga, InitiateSimpleSaga>(Mock.Of<IMongoCollection<SimpleSaga>>(), Mock.Of<ConsumeContext<InitiateSimpleSaga>>(), Mock.Of<SimpleSaga>()); _context = mongoDbSagaConsumeContext.PopContext<InitiateSimpleSaga>(); }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { SagaConsumeContext <TSaga, TMessage> sagaConsumeContext = await _repositoryContext.Add(context.Saga).ConfigureAwait(false); sagaConsumeContext.LogAdded(); try { await _next.Send(sagaConsumeContext).ConfigureAwait(false); } finally { switch (sagaConsumeContext) { case IAsyncDisposable asyncDisposable: await asyncDisposable.DisposeAsync().ConfigureAwait(false); break; case IDisposable disposable: disposable.Dispose(); break; } } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { var instance = context.Saga; if (_logger.IsDebugEnabled) { _logger.DebugFormat("SAGA: {0}:{1} Added {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId, TypeMetadataCache <TMessage> .ShortName); } SagaConsumeContext <TSaga, TMessage> proxy = new EventStoreSagaConsumeContext <TSaga, TMessage>(_connection, context, instance); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { await _connection.SaveEvents( instance.StreamName, instance.GetChanges(), instance.ExpectedVersion, new EventMetadata { CorrelationId = instance.CorrelationId, CausationId = context.MessageId }); } }
async Task SendToInstance <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next, TSaga instance) where T : class { try { if (_log.IsDebugEnabled) { _log.DebugFormat("SAGA:{0}:{1} Used {2}", TypeMetadataCache <TSaga> .ShortName, instance.CorrelationId, TypeMetadataCache <T> .ShortName); } SagaConsumeContext <TSaga, T> sagaConsumeContext = _documentDbSagaConsumeContextFactory.Create(_client, _databaseName, _collectionName, context, instance, true, _requestOptions); await policy.Existing(sagaConsumeContext, next).ConfigureAwait(false); if (!sagaConsumeContext.IsCompleted) { await UpdateDocumentDbSaga(context, instance).ConfigureAwait(false); } } catch (SagaException) { throw; } catch (Exception ex) { throw new SagaException(ex.Message, typeof(TSaga), typeof(T), instance.CorrelationId, ex); } }
public async Task Update <T>(SagaConsumeContext <TSaga, T> context) where T : class { var instance = context.Saga; IAsyncDisposable updateLock = _options.ConcurrencyMode == ConcurrencyMode.Optimistic ? updateLock = await Lock(instance, context.CancellationToken).ConfigureAwait(false) : null; try { instance.Version++; var existingInstance = await Get(instance.CorrelationId).ConfigureAwait(false); if (existingInstance.Version >= instance.Version) { throw new RedisSagaConcurrencyException("Saga version conflict", typeof(TSaga), typeof(T), instance.CorrelationId); } await Put(instance).ConfigureAwait(false); } catch (Exception exception) { throw new SagaException("Saga update failed", typeof(TSaga), typeof(T), instance.CorrelationId, exception); } finally { if (updateLock != null) { await updateLock.DisposeAsync(CancellationToken.None).ConfigureAwait(false); } } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { var instance = new SagaInstance <TSaga>(context.Saga); await instance.MarkInUse(context.CancellationToken).ConfigureAwait(false); try { var proxy = new InMemorySagaConsumeContext <TSaga, TMessage>(context, context.Saga, () => RemoveNewSaga(instance, context.CancellationToken)); if (_withinLock) { _repository.AddWithinLock(instance); } else { await _repository.Add(instance, context.CancellationToken).ConfigureAwait(false); } if (_log.IsDebugEnabled) { _log.DebugFormat("SAGA:{0}:{1} Added {2}", TypeMetadataCache <TSaga> .ShortName, context.Saga.CorrelationId, TypeMetadataCache <TMessage> .ShortName); } try { await _next.Send(proxy).ConfigureAwait(false); if (proxy.IsCompleted) { if (_log.IsDebugEnabled) { _log.DebugFormat("SAGA:{0}:{1} Removed {2}", TypeMetadataCache <TSaga> .ShortName, context.Saga.CorrelationId, TypeMetadataCache <TMessage> .ShortName); } await RemoveNewSaga(instance, context.CancellationToken).ConfigureAwait(false); } } catch (Exception) { if (_log.IsDebugEnabled) { _log.DebugFormat("SAGA:{0}:{1} Removed(Fault) {2}", TypeMetadataCache <TSaga> .ShortName, context.Saga.CorrelationId, TypeMetadataCache <TMessage> .ShortName); } await RemoveNewSaga(instance, context.CancellationToken).ConfigureAwait(false); throw; } } finally { instance.Release(); } }
public Task Send(SagaConsumeContext <TSaga> context) { if (context is SagaConsumeContext <TSaga, TMessage> consumerContext) { return(_output.Send(consumerContext)); } throw new ArgumentException($"THe message could not be retrieved: {TypeMetadataCache<TMessage>.ShortName}", nameof(context)); }
public async Task Send(SagaRepositoryContext <TSaga, T> context) { SagaConsumeContext <TSaga, T> sagaConsumeContext = null; if (_policy.PreInsertInstance(context, out var instance)) { sagaConsumeContext = await context.Insert(instance).ConfigureAwait(false); } sagaConsumeContext ??= await context.Load(_correlationId).ConfigureAwait(false); if (sagaConsumeContext != null) { try { sagaConsumeContext.LogUsed(); await _policy.Existing(sagaConsumeContext, _next).ConfigureAwait(false); if (_policy.IsReadOnly) { await context.Undo(sagaConsumeContext).ConfigureAwait(false); } else { if (sagaConsumeContext.IsCompleted) { await context.Delete(sagaConsumeContext).ConfigureAwait(false); sagaConsumeContext.LogRemoved(); } else { await context.Update(sagaConsumeContext).ConfigureAwait(false); } } } finally { switch (sagaConsumeContext) { case IAsyncDisposable asyncDisposable: await asyncDisposable.DisposeAsync().ConfigureAwait(false); break; case IDisposable disposable: disposable.Dispose(); break; } } } else { await _policy.Missing(context, new MissingSagaPipe <TSaga, T>(context, _next)).ConfigureAwait(false); } }
public async Task GivenAMongoDbQuerySagaRepository_WhenFindingSaga() { _correlationId = Guid.NewGuid(); await SagaRepository.InsertSaga(new SimpleSaga { CorrelationId = _correlationId }); var repository = new MongoDbSagaRepositoryContext <SimpleSaga, InitiateSimpleSaga>(SagaRepository.Instance.GetCollection <SimpleSaga>("sagas"), Mock.Of <ConsumeContext <InitiateSimpleSaga> >(), new MongoDbSagaConsumeContextFactory <SimpleSaga>()); _result = await repository.Load(_correlationId); }
public Task Send(ConsumeContext <TMessage> context) { if (ReferenceEquals(context, _context)) { return(_output.Send(_context)); } SagaConsumeContext <TSaga, TMessage> sagaContext = context as SagaConsumeContext <TSaga, TMessage> ?? new SagaConsumeContextProxy <TSaga, TMessage>(context, _context); return(_output.Send(sagaContext)); }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { var sagaConsumeContext = new DapperSagaConsumeContext <TSaga, TMessage>(_sqlConnection, context, context.Saga, _tableName, false); sagaConsumeContext.LogAdded(); await _next.Send(sagaConsumeContext).ConfigureAwait(false); if (!sagaConsumeContext.IsCompleted) { await _insertSagaInstance(_sqlConnection, context.Saga).ConfigureAwait(false); } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { SagaConsumeContext <TSaga, TMessage> proxy = _mongoDbSagaConsumeContextFactory.Create(_collection, context, context.Saga, false); proxy.LogAdded(); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { await _collection.InsertOneAsync(context.Saga).ConfigureAwait(false); } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { SagaConsumeContext <TSaga, TMessage> proxy = new RedisSagaConsumeContext <TSaga, TMessage>(_sagas, context, context.Saga); proxy.LogAdded(); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { await _sagas.Put(context.Saga.CorrelationId, context.Saga).ConfigureAwait(false); } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { context.LogAdded(); SagaConsumeContext <TSaga, TMessage> proxy = new NHibernateSagaConsumeContext <TSaga, TMessage>(_session, context, context.Saga); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { await _session.SaveAsync(context.Saga).ConfigureAwait(false); } }
public Task Send(SagaConsumeContext <TInstance, TMessage> context, IPipe <SagaConsumeContext <TInstance, TMessage> > next) { if (context.TryGetPayload(out TScope _)) { _taskCompletionSource.TrySetResult(context); } else { _taskCompletionSource.TrySetException(new PayloadException("Service Provider not found")); } return(next.Send(context)); }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { var instance = new SagaInstance <TSaga>(context.Saga); await instance.MarkInUse(context.CancellationToken).ConfigureAwait(false); var activity = LogContext.IfEnabled(OperationName.Saga.Add)?.StartActivity(new { context.Saga.CorrelationId }); try { var sagaConsumeContext = new InMemorySagaConsumeContext <TSaga, TMessage>(context, context.Saga, () => RemoveNewSaga(instance, context.CancellationToken)); if (_withinLock) { _repository.AddWithinLock(instance); } else { await _repository.Add(instance, context.CancellationToken).ConfigureAwait(false); } sagaConsumeContext.LogAdded(); try { await _next.Send(sagaConsumeContext).ConfigureAwait(false); if (sagaConsumeContext.IsCompleted) { await RemoveNewSaga(instance, context.CancellationToken).ConfigureAwait(false); sagaConsumeContext.LogRemoved(); } } catch (Exception exception) { await RemoveNewSaga(instance, context.CancellationToken).ConfigureAwait(false); sagaConsumeContext.LogRemoved(exception); throw; } } finally { instance.Release(); activity?.Stop(); } }
public async Task Send(SagaConsumeContext<TSaga, TMessage> context, IPipe<SagaConsumeContext<TSaga, TMessage>> next) { var saga = context.Saga as InitiatedBy<TMessage>; if (saga == null) { string message = $"Saga type {TypeMetadataCache<TSaga>.ShortName} is not initiated by message type {TypeMetadataCache<TMessage>.ShortName}"; throw new ConsumerMessageException(message); } await saga.Consume(context).ConfigureAwait(false); await next.Send(context).ConfigureAwait(false); }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context) { SagaConsumeContext <TSaga, TMessage> proxy = new MartenSagaConsumeContext <TSaga, TMessage>(_session, context, context.Saga); proxy.LogAdded(); await _next.Send(proxy).ConfigureAwait(false); if (!proxy.IsCompleted) { _session.Store(context.Saga); await _session.SaveChangesAsync().ConfigureAwait(false); } }
public async Task Add <T>(SagaConsumeContext <TSaga, T> context) where T : class { var instance = context.Saga; try { await Put(instance).ConfigureAwait(false); } catch (Exception exception) { throw new SagaException("Saga update failed", typeof(TSaga), typeof(T), instance.CorrelationId, exception); } }
public async Task Send(SagaConsumeContext <TSaga, TMessage> context, IPipe <SagaConsumeContext <TSaga, TMessage> > next) { StartedActivity?activity = LogContext.IfEnabled(OperationName.Saga.InitiateOrOrchestrate)?.StartSagaActivity(context); try { await context.Saga.Consume(context).ConfigureAwait(false); await next.Send(context).ConfigureAwait(false); } finally { activity?.Stop(); } }