async Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next) { Stopwatch timer = Stopwatch.StartNew(); try { ISagaQuery <TSaga> query = _queryFactory.CreateQuery(context); SagaQueryConsumeContext <TSaga, TMessage> queryContext = new SagaQueryConsumeContextProxy <TSaga, TMessage>(context, query); await Task.Yield(); await _sagaRepository.SendQuery(queryContext, _policy, _messagePipe).ConfigureAwait(false); await next.Send(context).ConfigureAwait(false); await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName).ConfigureAwait(false); } catch (Exception ex) { await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName, ex).ConfigureAwait(false); throw; } }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { var dbContext = _dbContextFactory.CreateScoped(context); try { var lockContext = await _lockStrategy.CreateLockContext(dbContext, query, context.CancellationToken).ConfigureAwait(false); var repositoryContext = new DbContextSagaRepositoryContext <TSaga, T>(dbContext, context, _consumeContextFactory, _lockStrategy); await WithinTransaction(dbContext, async() => { var instances = await lockContext.Load().ConfigureAwait(false); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances); await next.Send(queryContext).ConfigureAwait(false); }).ConfigureAwait(false); } finally { _dbContextFactory.Release(dbContext); } }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { return(await _collection.Find(query.FilterExpression) .Project(x => x.CorrelationId) .ToListAsync() .ConfigureAwait(false)); }
public Task SendQuery <T>( ConsumeContext <T> context, ISagaQuery <TSaga> query, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next ) where T : class { throw new NotImplementedByDesignException("EventStore saga repository does not support queries"); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next) where T : class { try { await _repositoryContextFactory.SendQuery(context, query, new SendQuerySagaPipe <TSaga, T>(policy, next)).ConfigureAwait(false); } catch (SagaException exception) { context.LogFault(this, exception); throw; } catch (DataException exception) { context.LogFault(this, exception); throw; } catch (Exception exception) { context.LogFault(this, exception); throw new SagaException(exception.Message, typeof(TSaga), typeof(T), Guid.Empty, exception); } }
public static async Task <Guid?> ShouldContainSagaInState <TStateMachine, TInstance>(this ISagaRepository <TInstance> repository, Expression <Func <TInstance, bool> > expression, TStateMachine machine, State state, TimeSpan timeout) where TStateMachine : SagaStateMachine <TInstance> where TInstance : class, SagaStateMachineInstance { var querySagaRepository = repository as IQuerySagaRepository <TInstance>; if (querySagaRepository == null) { throw new ArgumentException("The repository must support querying", nameof(repository)); } var giveUpAt = DateTime.Now + timeout; ISagaQuery <TInstance> query = machine.CreateSagaQuery(expression, state); while (DateTime.Now < giveUpAt) { var saga = (await querySagaRepository.Find(query).ConfigureAwait(false)).FirstOrDefault(); if (saga != Guid.Empty) { return(saga); } await Task.Delay(10).ConfigureAwait(false); } return(default);
public OptimisticSagaLockContext(DbContext context, ISagaQuery <TSaga> query, CancellationToken cancellationToken, ILoadQueryProvider <TSaga> provider) { _context = context; _query = query; _cancellationToken = cancellationToken; _provider = provider; }
public async Task <SagaRepositoryQueryContext <TSaga> > Query(ISagaQuery <TSaga> query, CancellationToken cancellationToken = default) { IReadOnlyList <TSaga> instances = await _session.Query <TSaga>() .Where(query.FilterExpression) .ToListAsync(cancellationToken).ConfigureAwait(false); return(new LoadedSagaRepositoryQueryContext <TSaga>(this, instances)); }
Task ISagaRepository <TSaga> .SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next) { var interceptPipe = new InterceptPipe <T>(_sagas, _received, next); var interceptPolicy = new InterceptPolicy <T>(_created, policy); return(_sagaRepository.SendQuery(context, query, interceptPolicy, interceptPipe)); }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { IEnumerable <TSaga> sagas = await _client.CreateDocumentQuery <TSaga>(UriFactory.CreateDocumentCollectionUri(_databaseName, _collectionName), _feedOptions) .Where(query.FilterExpression) .QueryAsync() .ConfigureAwait(false); return(sagas.Select(x => x.CorrelationId)); }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { // This will not work for Document Db because the .Where needs to look for [JsonProperty("id")], and if you pass in CorrelationId property, the ISaga doesn't have that property. IEnumerable <TSaga> sagas = await _client.CreateDocumentQuery <TSaga>(UriFactory.CreateDocumentCollectionUri(_databaseName, _collectionName), _feedOptions) .Where(query.FilterExpression) .QueryAsync() .ConfigureAwait(false); return(sagas.Select(x => x.CorrelationId)); }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { using (var session = _sessionFactory.OpenSession()) { return(await session.QueryOver <TSaga>() .Where(query.FilterExpression) .Select(x => x.CorrelationId) .ListAsync <Guid>().ConfigureAwait(false)); } }
async Task <IEnumerable <Guid> > IQuerySagaRepository <TSaga> .Find(ISagaQuery <TSaga> query) { using (var dbContext = _sagaDbContextFactory()) { return(await dbContext.Set <TSaga>() .Where(query.FilterExpression) .Select(x => x.CorrelationId) .ToListAsync().ConfigureAwait(false)); } }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { using (var session = _store.QuerySession()) { return(await session.Query <TSaga>() .Where(query.FilterExpression) .Select(x => x.CorrelationId) .ToListAsync()); } }
public async Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { using (var session = OpenSession()) { return(await session.Query <TSaga>() .Where(query.FilterExpression) .Customize(x => x.WaitForNonStaleResultsAsOf(DateTime.Now + TimeSpan.FromMinutes(1))) .Select(x => x.CorrelationId) .ToListAsync()); } }
async Task <IEnumerable <Guid> > IQuerySagaRepository <TSaga> .Find(ISagaQuery <TSaga> query) { using (var connection = new SqlConnection(_connectionString)) { var tableName = GetTableName <TSaga>(); var(whereStatement, parameters) = WhereStatementHelper.GetWhereStatementAndParametersFromExpression(query.FilterExpression); return ((await connection.QueryAsync <Guid>($"SELECT CorrelationId FROM {tableName} WITH (UPDLOCK, ROWLOCK) {whereStatement}", parameters).ConfigureAwait(false)).ToList()); } }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { var repositoryContext = new MongoDbSagaRepositoryContext <TSaga, T>(_mongoCollection, context, _factory); IList <TSaga> instances = await _mongoCollection.Find(query.FilterExpression) .ToListAsync(repositoryContext.CancellationToken) .ConfigureAwait(false); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances); await next.Send(queryContext).ConfigureAwait(false); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { await _sagas.MarkInUse(context.CancellationToken).ConfigureAwait(false); using var repositoryContext = new InMemorySagaRepositoryContext <TSaga, T>(_sagas, _factory, context); var matchingInstances = _sagas.Where(query).Select(x => x.Instance.CorrelationId).ToList(); var queryContext = new DefaultSagaRepositoryQueryContext <TSaga, T>(repositoryContext, matchingInstances); await next.Send(queryContext).ConfigureAwait(false); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { IEnumerable <TSaga> sagas = await _context.Container.GetItemLinqQueryable <TSaga>() .Where(query.FilterExpression) .QueryAsync(context.CancellationToken) .ConfigureAwait(false); var repositoryContext = new CosmosSagaRepositoryContext <TSaga, T>(_context, context, _factory); var queryContext = new DefaultSagaRepositoryQueryContext <TSaga, T>(repositoryContext, sagas.Select(x => x.CorrelationId).ToList()); await next.Send(queryContext).ConfigureAwait(false); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { using DapperDatabaseContext <TSaga> databaseContext = await CreateDatabaseContext(context.CancellationToken).ConfigureAwait(false); IEnumerable <TSaga> instances = await databaseContext.QueryAsync(query.FilterExpression, context.CancellationToken).ConfigureAwait(false); var repositoryContext = new DapperSagaRepositoryContext <TSaga, T>(databaseContext, context, _factory); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances); await next.Send(queryContext).ConfigureAwait(false); databaseContext.Commit(); }
public Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew)) using (var session = _sessionFactory.OpenSession()) { IList <Guid> result = session.QueryOver <TSaga>() .Where(query.FilterExpression) .Select(x => x.CorrelationId) .List <Guid>(); scope.Complete(); return(Task.FromResult <IEnumerable <Guid> >(result)); } }
public IEnumerable <SagaInstance <TSaga> > Where(ISagaQuery <TSaga> query) { lock (_lock) { IIndexedSagaProperty <TSaga> index = HasIndexFor(query.FilterExpression); if (index == null) { return(_indexById.Where(query.GetFilter()).ToList()); } var rightValue = GetRightValue(query.FilterExpression); return(index.Where(rightValue, query.GetFilter()).ToList()); } }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { // This will not work for Document Db because the .Where needs to look for [JsonProperty("id")], // and if you pass in CorrelationId property, the ISaga doesn't have that property. Can we .Select() it out? IEnumerable <TSaga> sagas = await _context.Client.CreateDocumentQuery <TSaga>(_context.Collection, _context.FeedOptions) .Where(query.FilterExpression) .QueryAsync(context.CancellationToken) .ConfigureAwait(false); var repositoryContext = new DocumentDbSagaRepositoryContext <TSaga, T>(_context, context, _factory); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, sagas.ToList()); await next.Send(queryContext).ConfigureAwait(false); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { using var session = _documentStore.DirtyTrackedSession(); var repositoryContext = new MartenSagaRepositoryContext <TSaga, T>(session, context, _factory); IReadOnlyList <TSaga> instances = await session.Query <TSaga>() .Where(query.FilterExpression) .ToListAsync().ConfigureAwait(false); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances.ToList()); await next.Send(queryContext).ConfigureAwait(false); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { var session = _sessionFactory.OpenSession(); ITransaction transaction = null; try { transaction = session.BeginTransaction(); var repositoryContext = new NHibernateSagaRepositoryContext <TSaga, T>(session, context, _factory); IList <TSaga> instances = await session.QueryOver <TSaga>() .Where(query.FilterExpression) .ListAsync(repositoryContext.CancellationToken) .ConfigureAwait(false); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances); await next.Send(queryContext).ConfigureAwait(false); await transaction.CommitAsync(repositoryContext.CancellationToken).ConfigureAwait(false); } catch (Exception) { if (transaction != null && transaction.IsActive) { try { await transaction.RollbackAsync(context.CancellationToken).ConfigureAwait(false); } catch (Exception rollbackException) { LogContext.Warning?.Log(rollbackException, "Failed to rollback transaction"); } } throw; } finally { transaction?.Dispose(); session.Dispose(); } }
async Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next) { Stopwatch timer = Stopwatch.StartNew(); var activity = LogContext.IfEnabled(OperationName.Saga.SendQuery)?.StartActivity(new { SagaType = TypeMetadataCache <TSaga> .ShortName, MessageType = TypeMetadataCache <TMessage> .ShortName }); try { ISagaQuery <TSaga> query = _queryFactory.CreateQuery(context); SagaQueryConsumeContext <TSaga, TMessage> queryContext = new SagaQueryConsumeContextScope <TSaga, TMessage>(context, query); await Task.Yield(); await _sagaRepository.SendQuery(queryContext, _policy, _messagePipe).ConfigureAwait(false); await next.Send(context).ConfigureAwait(false); await context.NotifyConsumed(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName).ConfigureAwait(false); } catch (OperationCanceledException exception) { await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName, exception).ConfigureAwait(false); if (exception.CancellationToken == context.CancellationToken) { throw; } throw new ConsumerCanceledException($"The operation was cancelled by the consumer: {TypeMetadataCache<TSaga>.ShortName}"); } catch (Exception ex) { await context.NotifyFaulted(timer.Elapsed, TypeMetadataCache <TSaga> .ShortName, ex).ConfigureAwait(false); throw; } finally { activity?.Stop(); } }
public async Task <SagaRepositoryQueryContext <TSaga> > Query(ISagaQuery <TSaga> query, CancellationToken cancellationToken = default) { QueryRequestOptions queryOptions = null; if (_context.QueryRequestOptions != null) { queryOptions = new QueryRequestOptions(); _context.QueryRequestOptions?.Invoke(queryOptions); } // This will not work for Document Db because the .Where needs to look for [JsonProperty("id")], // and if you pass in CorrelationId property, the ISaga doesn't have that property. Can we .Select() it out? IEnumerable <TSaga> instances = await _context.Container.GetItemLinqQueryable <TSaga>(requestOptions : queryOptions) .Where(query.FilterExpression) .QueryAsync(cancellationToken) .ConfigureAwait(false); return(new LoadedSagaRepositoryQueryContext <TSaga>(this, instances)); }
public async Task SendQuery <T>(ConsumeContext <T> context, ISagaQuery <TSaga> query, IPipe <SagaRepositoryQueryContext <TSaga, T> > next) where T : class { var dbContext = _dbContextFactory.CreateScoped(context); try { async Task Send() { SagaLockContext <TSaga> lockContext = await _lockStrategy.CreateLockContext(dbContext, query, context.CancellationToken).ConfigureAwait(false); var repositoryContext = new DbContextSagaRepositoryContext <TSaga, T>(dbContext, context, _consumeContextFactory, _lockStrategy); await WithinTransaction(dbContext, context.CancellationToken, async() => { IList <TSaga> instances = await lockContext.Load().ConfigureAwait(false); var queryContext = new LoadedSagaRepositoryQueryContext <TSaga, T>(repositoryContext, instances); await next.Send(queryContext).ConfigureAwait(false); }).ConfigureAwait(false); } var executionStrategy = dbContext.Database.CreateExecutionStrategy(); if (executionStrategy is ExecutionStrategy) { await executionStrategy.ExecuteAsync(Send).ConfigureAwait(false); } else { await Send().ConfigureAwait(false); } } finally { await _dbContextFactory.ReleaseAsync(dbContext).ConfigureAwait(false); } }
/// <summary> /// Waits until a saga exists with the specified correlationId in the specified state /// </summary> /// <param name="correlationId"></param> /// <param name="state">The expected state</param> /// <param name="timeout"></param> /// <returns></returns> public async Task <Guid?> Exists(Guid correlationId, State state, TimeSpan?timeout = default) { if (QuerySagaRepository == null) { throw new InvalidOperationException("The repository does not support Query operations"); } var giveUpAt = DateTime.Now + (timeout ?? TestTimeout); ISagaQuery <TInstance> query = _stateMachine.CreateSagaQuery(x => x.CorrelationId == correlationId, state); while (DateTime.Now < giveUpAt) { var saga = (await QuerySagaRepository.Find(query).ConfigureAwait(false)).FirstOrDefault(); if (saga != Guid.Empty) { return(saga); } await Task.Delay(10).ConfigureAwait(false); } return(default);
public Task <IEnumerable <Guid> > Find(ISagaQuery <TSaga> query) { return(Task.FromResult(_sagas.Where(query).Select(x => x.Instance.CorrelationId))); }