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