Пример #1
0
        /// <summary>
        /// Enables async/await-based request/reply whereby a request can be sent using the <see cref="AsyncBusExtensions.SendRequest{TReply}"/> method
        /// which can be awaited for a corresponding reply.
        /// </summary>
        public static void EnableSynchronousRequestReply(this OptionsConfigurer configurer, int replyMaxAgeSeconds = 10)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            if (replyMaxAgeSeconds <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(replyMaxAgeSeconds), replyMaxAgeSeconds,
                                                      "Please supply a positive value for the max age of a reply (i.e. how long to keep a reply until we give up on returning it)");
            }

            configurer.Register(c =>
            {
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                var asyncTaskFactory   = c.Get <IAsyncTaskFactory>();
                var replyMaxAge        = TimeSpan.FromSeconds(replyMaxAgeSeconds);
                var step = new ReplyHandlerStep(AsyncBusExtensions.Messages, rebusLoggerFactory, asyncTaskFactory, replyMaxAge);
                return(step);
            });

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var step     = c.Get <ReplyHandlerStep>();
                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.Before, typeof(ActivateHandlersStep)));
            });
        }
        /// <summary>
        /// Makes Rebus "legacy compatible", i.e. enables wire-level compatibility with older Rebus versions. WHen this is enabled,
        /// all endpoints need to be old Rebus endpoints or new Rebus endpoints with this feature enabled
        /// </summary>
        public static void EnableLegacyCompatibility(this OptionsConfigurer configurer, Encoding encoding, bool propagateAutoCorrelationSagaId = true)
        {
            configurer.Register <ISerializer>(c =>
            {
                return(new LegacyCompatibilitySerializer(encoding ?? LegacyCompatibilitySerializer.DefaultEncoding));
            });

            configurer.Decorate(c =>
            {
                var pipeline = c.Get <IPipeline>();

                pipeline = new PipelineStepConcatenator(pipeline)
                           .OnReceive(new MapLegacyHeadersIncomingStep(propagateAutoCorrelationSagaId), PipelineAbsolutePosition.Front);

                // unpack object[] of transport message
                pipeline = new PipelineStepInjector(pipeline)
                           .OnReceive(new UnpackLegacyMessageIncomingStep(), PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep));

                // pack into object[]
                pipeline = new PipelineStepInjector(pipeline)
                           .OnSend(new PackLegacyMessageOutgoingStep(), PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep));

                pipeline = new PipelineStepInjector(pipeline)
                           .OnSend(new MapLegacyHeadersOutgoingStep(propagateAutoCorrelationSagaId), PipelineRelativePosition.Before, typeof(SendOutgoingMessageStep));

                return(pipeline);
            });
        }
        public static void EnableDiagnosticSources(this OptionsConfigurer configurer)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var injector = new PipelineStepInjector(pipeline);

                var outgoingStep = new OutgoingDiagnosticsStep();
                injector.OnSend(outgoingStep, PipelineRelativePosition.Before,
                                typeof(SendOutgoingMessageStep));

                var incomingStep = new IncomingDiagnosticsStep();

                var invokerWrapper = new IncomingDiagnosticsHandlerInvokerWrapper();
                injector.OnReceive(invokerWrapper, PipelineRelativePosition.After, typeof(ActivateHandlersStep));

                var concatenator = new PipelineStepConcatenator(injector);
                concatenator.OnReceive(incomingStep, PipelineAbsolutePosition.Front);

                return(concatenator);
            });
        }
        /// <summary>
        /// Enabling fluent configuration of circuit breakers
        /// </summary>
        /// <param name="configurer"></param>
        /// <param name="circuitBreakerBuilder"></param>
        public static void EnableCircuitBreaker(this OptionsConfigurer configurer, Action <CircuitBreakerConfigurationBuilder> circuitBreakerBuilder)
        {
            var builder = new CircuitBreakerConfigurationBuilder();

            circuitBreakerBuilder?.Invoke(builder);

            configurer.Register(context => new CircuitBreakerEvents());

            configurer.Register(context =>
            {
                var loggerFactory        = context.Get <IRebusLoggerFactory>();
                var asyncTaskFactory     = context.Get <IAsyncTaskFactory>();
                var circuitBreakerEvents = context.Get <CircuitBreakerEvents>();
                var options         = context.Get <Options>();
                var circuitBreakers = builder.Build(context);

                return(new MainCircuitBreaker(circuitBreakers, loggerFactory, asyncTaskFactory, new Lazy <IBus>(context.Get <IBus>), circuitBreakerEvents, options));
            });

            configurer.Decorate <IErrorTracker>(context =>
            {
                var innerErrorTracker = context.Get <IErrorTracker>();
                var circuitBreaker    = context.Get <MainCircuitBreaker>();

                return(new CircuitBreakerErrorTracker(innerErrorTracker, circuitBreaker));
            });
        }
Пример #5
0
        /// <summary>
        /// Enables auto-scaling. When enabled, the bus will always start out with one single worker, possibly adding workers
        /// up until <paramref name="maxNumberOfWorkers"/>.
        /// Max parallelism can be set with <paramref name="maxParallelism"/>, which would otherwise default to the same as the
        /// number of workers.
        /// At most one worker will be added/removed, and the interval with which this happens is configured by setting
        /// <paramref name="adjustmentIntervalSeconds"/> (default: 10 s)
        /// </summary>
        public static void EnableAutoScaling(this OptionsConfigurer configurer, int maxNumberOfWorkers, int?maxParallelism = null, int adjustmentIntervalSeconds = 10)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }
            if (adjustmentIntervalSeconds < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(adjustmentIntervalSeconds), adjustmentIntervalSeconds,
                                                      "Please provide a value of at least 1 for the adjustment interval");
            }

            // decorate the transport so the auto-scaler gets to see how many messages are received
            configurer.Decorate <ITransport>(c => c.Get <AutoScaler>());

            // register auto-scaler
            configurer.Register(c =>
            {
                var options = c.Get <Options>();

                options.MaxParallelism  = maxParallelism ?? maxNumberOfWorkers;
                options.NumberOfWorkers = 1;

                var transport          = c.Get <ITransport>();
                var asyncTaskFactory   = c.Get <IAsyncTaskFactory>();
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();

                return(new AutoScaler(transport, rebusLoggerFactory, maxNumberOfWorkers, asyncTaskFactory, c.Get <IBus>, adjustmentIntervalSeconds));
            });
        }
        public static void IncludePrincipalClaims(this OptionsConfigurer configurer, IServiceProvider provider)
        {
            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var step     = provider.GetRequiredService <IncludePrincipalClaimsStep>();

                return(new PipelineStepInjector(pipeline)
                       .OnSend(step, PipelineRelativePosition.Before, typeof(AutoHeadersOutgoingStep)));
            });
            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var step     = provider.GetRequiredService <IncludePrincipalClaimsStep>();

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep)));
            });
        }
Пример #7
0
        /// <summary>
        /// Registers a step which set and load the message id header from IMessage.MessageId
        /// </summary>
        /// <param name="configurer"></param>
        public static void AutoSetMessageId(this OptionsConfigurer configurer)
        {
            var step = new AutoSetMessageIdStep();

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();

                return(new PipelineStepInjector(pipeline)
                       .OnSend(step, PipelineRelativePosition.Before, typeof(AssignDefaultHeadersStep)));
            });
            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)));
            });
        }
Пример #8
0
        /// <summary>
        /// Registers a step which the scope of each pipeline
        /// </summary>
        /// <param name="configurer"></param>
        /// <param name="provider"></param>
        public static void ApplyServiceProvider(this OptionsConfigurer configurer, IServiceProvider provider)
        {
            var step = new ServiceProviderStep(provider);

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline  = c.Get <IPipeline>();
                var retryStep = c.Get <IRetryStrategyStep>();

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.Before, retryStep.GetType()));
            });
            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();

                return(new PipelineStepInjector(pipeline)
                       .OnSend(step, PipelineRelativePosition.Before, typeof(AssignDefaultHeadersStep)));
            });
        }
Пример #9
0
        /// <summary>
        /// Registers a step which set and load the message id header from IMessage.MessageId
        /// </summary>
        /// <param name="configurer"></param>
        public static void CatchMessagesSent(this OptionsConfigurer configurer)
        {
            var step = new CatchMessagesSentStep();

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();

                return(new PipelineStepInjector(pipeline)
                       .OnSend(step, PipelineRelativePosition.After, typeof(SendOutgoingMessageStep)));
            });
        }
Пример #10
0
        /// <summary>
        /// Configures Rebus to execute handlers inside a <see cref="TransactionScope"/>, using the transaction options
        /// given by <paramref name="transactionOptions"/> for the transaction scope.
        /// <para>
        /// The <see cref="TransactionScope"/> is managed with an <see cref="ITransport"/> decorator,
        /// which means that it gets created before receiving the incoming message.
        /// </para>
        /// <para>
        /// <code>
        /// Configure.With(..)<para/>
        ///     .(...)<para/>
        ///     .Options(o => o.LogPipeline(verbose: true)<para/>
        ///     .Start();<para/>
        /// </code>
        /// </para>
        /// </summary>
        public static void HandleMessagesInsideTransactionScope(this OptionsConfigurer configurer, TransactionOptions transactionOptions)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            configurer.Decorate <ITransport>(c =>
            {
                var transport = c.Get <ITransport>();

                return(new TransactionScopeTransportDecorator(transport, transactionOptions));
            });

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(new TransactionScopeIncomingStep(), PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep)));
            });
        }
Пример #11
0
        /// <summary>
        /// Configures Rebus to execute handlers inside a <see cref="TransactionScope"/>, using the transaction options
        /// given by <paramref name="transactionOptions"/> for the transaction scope
        /// </summary>
        public static void HandleMessagesInsideTransactionScope(this OptionsConfigurer configurer, TransactionOptions transactionOptions)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline     = c.Get <IPipeline>();
                var stepToInject = new TransactionScopeIncomingStep(transactionOptions);

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(stepToInject, PipelineRelativePosition.Before, typeof(DispatchIncomingMessageStep)));
            });
        }
Пример #12
0
        /// <summary>
        ///     Registers a custom IErrorHandler which emits events for any exceptions raised by a command
        /// </summary>
        /// <param name="configurer"></param>
        /// <param name="provider"></param>
        public static void HandleCommandsEvents(this OptionsConfigurer configurer, IServiceProvider provider)
        {
            configurer.Register <IErrorHandler>(c =>
            {
                var simpleRetryStrategySettings = c.Get <SimpleRetryStrategySettings>();
                var transport          = c.Get <ITransport>();
                var serializer         = c.Get <ISerializer>();
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                return(new CommandsErrorHandler(provider, serializer, simpleRetryStrategySettings, transport, rebusLoggerFactory));
            });

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var step     = new CompleteCommandEventStep(c.Get <IErrorTracker>(), provider);

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.After, typeof(DispatchIncomingMessageStep)));
            });
        }
        /// <summary>
        /// Enables async/await-based request/reply whereby a request can be sent using the <see cref="AsyncBusExtensions.SendRequest{TReply}"/> method
        /// which can be awaited for a corresponding reply.
        /// </summary>
        public static void EnableSynchronousRequestReply(this OptionsConfigurer configurer)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            configurer.Register(c =>
            {
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                var step = new ReplyHandlerStep(AsyncBusExtensions.Messages, rebusLoggerFactory);
                return(step);
            });

            configurer.Decorate <IPipeline>(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var step     = c.Get <ReplyHandlerStep>();
                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.Before, typeof(ActivateHandlersStep)));
            });
        }
        /// <summary>
        /// Makes Rebus "legacy compatible", i.e. enables wire-level compatibility with older Rebus versions. WHen this is enabled,
        /// all endpoints need to be old Rebus endpoints or new Rebus endpoints with this feature enabled
        /// </summary>
        public static void EnableLegacyCompatibility(this OptionsConfigurer configurer)
        {
            configurer.Register(c => new LegacyFlag());

            configurer.Register <ISerializer>(c =>
            {
                var specialSettings = LegacySubscriptionMessagesBinder.JsonSerializerSettings;
                var legacyEncoding  = Encoding.UTF7;
                var jsonSerializer  = new CustomJsonSerializer(specialSettings, legacyEncoding);
                return(jsonSerializer);
            });

            configurer.Decorate(c =>
            {
                var pipeline = c.Get <IPipeline>();

                // map headers of incoming message from v1 to v2
                pipeline = new PipelineStepConcatenator(pipeline)
                           .OnReceive(new MapLegacyHeadersIncomingStep(), PipelineAbsolutePosition.Front);

                // unpack object[] of transport message
                pipeline = new PipelineStepInjector(pipeline)
                           .OnReceive(new UnpackLegacyMessageIncomingStep(), PipelineRelativePosition.After, typeof(DeserializeIncomingMessageStep));

                // pack into object[]
                pipeline = new PipelineStepInjector(pipeline)
                           .OnSend(new PackLegacyMessageOutgoingStep(), PipelineRelativePosition.Before, typeof(SerializeOutgoingMessageStep));

                pipeline = new PipelineStepInjector(pipeline)
                           .OnSend(new MapLegacyHeadersOutgoingStep(), PipelineRelativePosition.Before, typeof(SendOutgoingMessageStep));

                //pipeline = new PipelineStepInjector(pipeline)
                //    .OnReceive(new HandleLegacySubscriptionRequestIncomingStep(c.Get<ISubscriptionStorage>(), c.Get<LegacySubscriptionMessageSerializer>()), PipelineRelativePosition.Before, typeof(MapLegacyHeadersIncomingStep));

                return(pipeline);
            });
        }
Пример #15
0
        /// <summary>
        /// Wraps the invocation of the incoming pipeline in a step that creates a unit of work, committing/rolling back depending on how the invocation of the pipeline went. The cleanup action is always called.
        /// </summary>
        public static void EnableAsyncUnitOfWork <TUnitOfWork>(this OptionsConfigurer configurer,
                                                               Func <IMessageContext, Task <TUnitOfWork> > create,
                                                               Func <IMessageContext, TUnitOfWork, Task> commit,
                                                               Func <IMessageContext, TUnitOfWork, Task> rollback = null,
                                                               Func <IMessageContext, TUnitOfWork, Task> dispose  = null)
        {
            if (create == null)
            {
                throw new ArgumentNullException(nameof(create), "You need to provide a factory method that is capable of creating new units of work");
            }
            if (commit == null)
            {
                throw new ArgumentNullException(nameof(commit), "You need to provide a commit action that commits the current unit of work");
            }

            configurer.Decorate <IPipeline>(context =>
            {
                var pipeline       = context.Get <IPipeline>();
                var unitOfWorkStep = new UnitOfWorkStep <TUnitOfWork>(create, commit, rollback, dispose);

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(unitOfWorkStep, PipelineRelativePosition.Before, typeof(ActivateHandlersStep)));
            });
        }