public static async Task Retry <T>(this IRetryPolicy retryPolicy, ConsumeContext <T> context,
                                           Func <ConsumeContext <T>, Task> retryMethod)
            where T : class
        {
            using (RetryPolicyContext <ConsumeContext <T> > policyContext = retryPolicy.CreatePolicyContext(context))
            {
                try
                {
                    await retryMethod(policyContext.Context).ConfigureAwait(false);
                }
                catch (Exception exception)
                {
                    RetryContext <ConsumeContext <T> > retryContext;
                    if (context.TryGetPayload(out retryContext))
                    {
                        throw;
                    }

                    if (!policyContext.CanRetry(exception, out retryContext))
                    {
                        context.GetOrAddPayload(() => retryContext);
                        throw;
                    }

                    await Attempt(retryContext, retryMethod).ConfigureAwait(false);
                }
            }
        }
예제 #2
0
        public void SetContext(ConsumeContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            lock (this)
            {
                if (_context == null)
                {
                    _context = context;
                    _marker  = new ScopedConsumeContext();

                    context.GetOrAddPayload(() => _marker);
                }
                else if (ReferenceEquals(_context, context))
                {
                }
                else if (!context.TryGetPayload <ScopedConsumeContext>(out _))
                {
                    throw new InvalidOperationException("The ConsumeContext was already set.");
                }
            }
        }
        Task Send <T>(ConsumeContext <T> context, Func <ConsumeContext <T>, ISagaRepositoryContextFactory <TSaga>, Task> send)
            where T : class
        {
            if (context.TryGetPayload <ILifetimeScope>(out var existingScope))
            {
                context.GetOrAddPayload(() => existingScope.ResolveOptional <IStateMachineActivityFactory>() ?? AutofacStateMachineActivityFactory.Instance);

                var factory = existingScope.Resolve <ISagaRepositoryContextFactory <TSaga> >();

                return(send(context, factory));
            }

            var parentLifetimeScope = _scopeProvider.GetLifetimeScope(context);

            async Task CreateScope()
            {
                await using var scope = parentLifetimeScope.BeginLifetimeScope(_name, builder =>
                {
                    builder.ConfigureScope(context);
                    _configureScope?.Invoke(builder, context);
                });

                var activityFactory = scope.ResolveOptional <IStateMachineActivityFactory>() ?? AutofacStateMachineActivityFactory.Instance;

                var consumeContext = scope.Resolve <ConsumeContext <T> >();

                var consumeContextScope = new ConsumeContextScope <T>(consumeContext, activityFactory);

                var factory = scope.Resolve <ISagaRepositoryContextFactory <TSaga> >();

                await send(consumeContextScope, factory).ConfigureAwait(false);
            }

            return(CreateScope());
        }
예제 #4
0
        Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            var schedulerContext = context.GetPayload <MessageSchedulerContext>();

            context.GetOrAddPayload <MessageRedeliveryContext>(() => new ScheduleMessageRedeliveryContext <TMessage>(context, schedulerContext));

            return(next.Send(context));
        }
예제 #5
0
        Task Send <T>(ConsumeContext <T> context, Func <ConsumeContext <T>, ISagaRepositoryContextFactory <TSaga>, Task> send)
            where T : class
        {
            if (!context.TryGetPayload(out IServiceProvider serviceProvider))
            {
                serviceProvider = _serviceProvider;
            }

            if (context.TryGetPayload <IServiceScope>(out var existingScope))
            {
                existingScope.SetCurrentConsumeContext(context);

                context.GetOrAddPayload(() => existingScope.ServiceProvider.GetService <IStateMachineActivityFactory>()
                                        ?? DependencyInjectionStateMachineActivityFactory.Instance);

                var factory = existingScope.ServiceProvider.GetRequiredService <ISagaRepositoryContextFactory <TSaga> >();

                return(send(context, factory));
            }

            async Task CreateScope()
            {
                var serviceScope = serviceProvider.CreateScope();

                try
                {
                    var scopeServiceProvider = new DependencyInjectionScopeServiceProvider(serviceScope.ServiceProvider);

                    var scopeContext = new ConsumeContextScope <T>(context, serviceScope, serviceScope.ServiceProvider, scopeServiceProvider);

                    serviceScope.SetCurrentConsumeContext(scopeContext);

                    var activityFactory = serviceScope.ServiceProvider.GetService <IStateMachineActivityFactory>()
                                          ?? DependencyInjectionStateMachineActivityFactory.Instance;

                    var consumeContextScope = new ConsumeContextScope <T>(scopeContext, activityFactory);

                    var factory = serviceScope.ServiceProvider.GetRequiredService <ISagaRepositoryContextFactory <TSaga> >();

                    await send(consumeContextScope, factory).ConfigureAwait(false);
                }
                finally
                {
                    if (serviceScope is IAsyncDisposable asyncDisposable)
                    {
                        await asyncDisposable.DisposeAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        serviceScope.Dispose();
                    }
                }
            }

            return(CreateScope());
        }
예제 #6
0
        Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            context.GetOrAddPayload <MessageRedeliveryContext>(() =>
            {
                var provider = new ActiveMqScheduleMessageProvider(context);

                return(new ActiveMqMessageRedeliveryContext <TMessage>(context, new MessageScheduler(provider)));
            });

            return(next.Send(context));
        }
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            using (var lifetimeScope = _scope.BeginLifetimeScope(_name, x => ConfigureScope(x, context)))
            {
                ConsumeContext <T> proxy = context.CreateScope(lifetimeScope);

                proxy.GetOrAddPayload <IStateMachineActivityFactory>(() => new AutofacStateMachineActivityFactory());

                await _repository.Send(proxy, policy, next).ConfigureAwait(false);
            }
        }
예제 #8
0
        Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            context.GetOrAddPayload <MessageRedeliveryContext>(() =>
            {
                var modelContext = context.ReceiveContext.GetPayload <SessionContext>();

                var provider = new DelayedExchangeScheduleMessageProvider(context, modelContext.ConnectionContext.Topology, modelContext.ConnectionContext.HostAddress);

                return(new DelayedExchangeMessageRedeliveryContext <TMessage>(context, new MessageScheduler(provider)));
            });

            return(next.Send(context));
        }
        Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            context.GetOrAddPayload <MessageRedeliveryContext>(() =>
            {
                var modelContext = context.ReceiveContext.GetPayload <ModelContext>();

                var scheduler = new DelayedExchangeMessageScheduler(context, modelContext.ConnectionContext.HostSettings);

                return(new DelayedExchangeMessageRedeliveryContext <TMessage>(context, scheduler));
            });

            return(next.Send(context));
        }
        public async Task Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            if (context.Headers.TryGetHeader(MessageHeaders.ClientId, out var obj) &&
                (obj is Guid clientId || obj is string s && Guid.TryParse(s, out clientId)))
            {
                var clientContext = await _clientCache.Link(clientId, context.ResponseAddress ?? context.SourceAddress).ConfigureAwait(false);

                clientContext.NotifyConsumed(context);

                context.GetOrAddPayload(() => clientContext);
            }

            await next.Send(context).ConfigureAwait(false);
        }
예제 #11
0
        async Task ISagaRepository <TSaga> .Send <T>(ConsumeContext <T> context, ISagaPolicy <TSaga, T> policy, IPipe <SagaConsumeContext <TSaga, T> > next)
        {
            using (var nestedContainer = _container.GetNestedContainer())
            {
                ConsumeContext <T> proxy = context.CreateScope(nestedContainer);

                nestedContainer.Configure(x =>
                {
                    x.For <ConsumeContext>()
                    .Use(proxy);
                    x.For <ConsumeContext <T> >()
                    .Use(proxy);
                });

                proxy.GetOrAddPayload <IStateMachineActivityFactory>(() => new StructureMapStateMachineActivityFactory());

                await _repository.Send(proxy, policy, next).ConfigureAwait(false);
            }
        }
예제 #12
0
        Task Send <T>(ConsumeContext <T> context, Func <ConsumeContext <T>, ISagaRepositoryContextFactory <TSaga>, Task> send)
            where T : class
        {
            if (!context.TryGetPayload(out IServiceProvider serviceProvider))
            {
                serviceProvider = _serviceProvider;
            }

            if (context.TryGetPayload <IServiceScope>(out var existingScope))
            {
                existingScope.UpdateScope(context);

                context.GetOrAddPayload(() => existingScope.ServiceProvider.GetService <IStateMachineActivityFactory>()
                                        ?? DependencyInjectionStateMachineActivityFactory.Instance);

                var factory = existingScope.ServiceProvider.GetRequiredService <ISagaRepositoryContextFactory <TSaga> >();

                return(send(context, factory));
            }

            async Task CreateScope()
            {
                using var serviceScope = serviceProvider.CreateScope();

                var scopeServiceProvider = serviceScope.ServiceProvider;

                var scopeContext = new ConsumeContextScope <T>(context, serviceScope, scopeServiceProvider);

                serviceScope.UpdateScope(scopeContext);

                var activityFactory = scopeServiceProvider.GetService <IStateMachineActivityFactory>()
                                      ?? DependencyInjectionStateMachineActivityFactory.Instance;

                var consumeContextScope = new ConsumeContextScope <T>(scopeContext, activityFactory);

                var factory = scopeServiceProvider.GetRequiredService <ISagaRepositoryContextFactory <TSaga> >();

                await send(consumeContextScope, factory).ConfigureAwait(false);
            }

            return(CreateScope());
        }
예제 #13
0
        Task Send <T>(ConsumeContext <T> context, Func <ConsumeContext <T>, ISagaRepositoryContextFactory <TSaga>, Task> send)
            where T : class
        {
            if (context.TryGetPayload <Scope>(out var existingScope))
            {
                existingScope.UpdateScope(context);

                context.GetOrAddPayload(() => existingScope.TryGetInstance <IStateMachineActivityFactory>()
                                        ?? SimpleInjectorStateMachineActivityFactory.Instance);

                var factory = existingScope.GetInstance <ISagaRepositoryContextFactory <TSaga> >();

                return(send(context, factory));
            }

            var scope = AsyncScopedLifestyle.BeginScope(_container);

            async Task CreateNestedContainer()
            {
                try
                {
                    var scopeContext = new ConsumeContextScope <T>(context, scope);

                    scope.UpdateScope(scopeContext);

                    var activityFactory = scope.TryGetInstance <IStateMachineActivityFactory>()
                                          ?? SimpleInjectorStateMachineActivityFactory.Instance;

                    var consumeContextScope = new ConsumeContextScope <T>(scopeContext, activityFactory);

                    var factory = scope.GetInstance <ISagaRepositoryContextFactory <TSaga> >();

                    await send(consumeContextScope, factory).ConfigureAwait(false);
                }
                finally
                {
                    scope.Dispose();
                }
            }

            return(CreateNestedContainer());
        }
예제 #14
0
        Task Send <T>(ConsumeContext <T> context, Func <ConsumeContext <T>, ISagaRepositoryContextFactory <TSaga>, Task> send)
            where T : class
        {
            if (context.TryGetPayload <IKernel>(out var existingKernel))
            {
                existingKernel.UpdateScope(context);

                context.GetOrAddPayload(() => existingKernel.TryResolve <IStateMachineActivityFactory>() ?? WindsorStateMachineActivityFactory.Instance);

                var factory = existingKernel.Resolve <ISagaRepositoryContextFactory <TSaga> >();

                return(send(context, factory));
            }

            var scope = _kernel.CreateNewOrUseExistingMessageScope();

            async Task CreateMessageScope()
            {
                try
                {
                    var scopeContext = new ConsumeContextScope <T>(context, _kernel);

                    _kernel.UpdateScope(scopeContext);

                    var activityFactory = _kernel.TryResolve <IStateMachineActivityFactory>() ?? WindsorStateMachineActivityFactory.Instance;

                    var consumeContextScope = new ConsumeContextScope <T>(scopeContext, activityFactory);

                    var factory = _kernel.Resolve <ISagaRepositoryContextFactory <TSaga> >();

                    await send(consumeContextScope, factory).ConfigureAwait(false);
                }
                finally
                {
                    scope.Dispose();
                }
            }

            return(CreateMessageScope());
        }
        Task IFilter <ConsumeContext <TMessage> > .Send(ConsumeContext <TMessage> context, IPipe <ConsumeContext <TMessage> > next)
        {
            context.GetOrAddPayload <MessageRedeliveryContext>(() => new DelayedExchangeMessageRedeliveryContext <TMessage>(context));

            return(next.Send(context));
        }
예제 #16
0
        public async Task Send(ConsumeContext <T> context, IPipe <ConsumeContext <T> > next)
        {
            RetryPolicyContext <ConsumeContext <T> > policyContext = _retryPolicy.CreatePolicyContext(context);

            await _observers.PostCreate(policyContext).ConfigureAwait(false);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (context.CancellationToken.IsCancellationRequested)
                {
                    if (exception is OperationCanceledException canceledException && canceledException.CancellationToken == context.CancellationToken)
                    {
                        throw;
                    }

                    context.CancellationToken.ThrowIfCancellationRequested();
                }

                if (policyContext.Context.TryGetPayload(out RetryContext <ConsumeContext <T> > payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => payloadRetryContext);

                    throw;
                }

                if (policyContext.Context.TryGetPayload(out RetryContext genericRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => genericRetryContext);

                    throw;
                }

                if (!policyContext.CanRetry(exception, out RetryContext <ConsumeContext <T> > retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(retryContext).ConfigureAwait(false);

                    if (_retryPolicy.IsHandled(exception))
                    {
                        context.GetOrAddPayload(() => retryContext);
                    }

                    throw;
                }

                int previousDeliveryCount = context.Headers.Get(MessageHeaders.RedeliveryCount, default(int?)) ?? 0;
                for (int retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                        await _observers.RetryFault(retryContext).ConfigureAwait(false);

                        if (_retryPolicy.IsHandled(exception))
                        {
                            context.GetOrAddPayload(() => retryContext);
                        }

                        throw;
                    }
                }

                await _observers.PostFault(retryContext).ConfigureAwait(false);

                try
                {
                    if (!context.TryGetPayload(out MessageRedeliveryContext redeliveryContext))
                    {
                        throw new ContextException("The message redelivery context was not available to delay the message", exception);
                    }

                    var delay = retryContext.Delay ?? TimeSpan.Zero;

                    await redeliveryContext.ScheduleRedelivery(delay).ConfigureAwait(false);

                    await context.NotifyConsumed(context, context.ReceiveContext.ElapsedTime, TypeMetadataCache <RedeliveryRetryFilter <T> > .ShortName).ConfigureAwait(false);
                }
                catch (Exception redeliveryException)
                {
                    throw new ContextException("The message delivery could not be rescheduled", new AggregateException(redeliveryException, exception));
                }
            }
        }
예제 #17
0
 static void AddStateMachineActivityFactory(ConsumeContext context)
 {
     context.GetOrAddPayload(() => _activityFactory);
 }
예제 #18
0
 TPayload PipeContext.GetOrAddPayload <TPayload>(PayloadFactory <TPayload> payloadFactory)
 {
     return(_context.GetOrAddPayload(payloadFactory));
 }
예제 #19
0
        public async Task Send(ConsumeContext <T> context, IPipe <ConsumeContext <T> > next)
        {
            RetryPolicyContext <ConsumeContext <T> > policyContext = _retryPolicy.CreatePolicyContext(context);

            await _observers.PostCreate(policyContext).ConfigureAwait(false);

            try
            {
                await next.Send(policyContext.Context).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                RetryContext <ConsumeContext <T> > payloadRetryContext;
                if (context.TryGetPayload(out payloadRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(payloadRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext genericRetryContext;
                if (context.TryGetPayload(out genericRetryContext))
                {
                    await policyContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(genericRetryContext).ConfigureAwait(false);

                    throw;
                }

                RetryContext <ConsumeContext <T> > retryContext;
                if (!policyContext.CanRetry(exception, out retryContext))
                {
                    await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                    await _observers.RetryFault(retryContext).ConfigureAwait(false);

                    context.GetOrAddPayload(() => retryContext);
                    throw;
                }

                int previousDeliveryCount = context.Headers.Get(MessageHeaders.RedeliveryCount, default(int?)) ?? 0;
                for (int retryIndex = 0; retryIndex < previousDeliveryCount; retryIndex++)
                {
                    if (!retryContext.CanRetry(exception, out retryContext))
                    {
                        await retryContext.RetryFaulted(exception).ConfigureAwait(false);

                        await _observers.RetryFault(retryContext).ConfigureAwait(false);

                        context.GetOrAddPayload(() => retryContext);
                        throw;
                    }
                }

                await _observers.PostFault(retryContext).ConfigureAwait(false);

                try
                {
                    MessageRedeliveryContext redeliveryContext;
                    if (!context.TryGetPayload(out redeliveryContext))
                    {
                        throw new ContextException("The message redelivery context was not available to delay the message", exception);
                    }

                    var delay = retryContext.Delay ?? TimeSpan.Zero;

                    await redeliveryContext.ScheduleRedelivery(delay).ConfigureAwait(false);
                }
                catch (Exception redeliveryException)
                {
                    throw new ContextException("The message delivery could not be rescheduled", new AggregateException(redeliveryException, exception));
                }
            }
        }