static void Register(StandardConfigurer<ITransport> configurer, string inputQueueAddress, CloudStorageAccount storageAccount)
        {
            configurer.Register(c => new AzureStorageQueuesTransport(storageAccount, inputQueueAddress));

            configurer.OtherService<ITimeoutManager>().Register(c => new DisabledTimeoutManager(), description: AsqTimeoutManagerText);

            configurer.OtherService<IPipeline>().Decorate(c =>
            {
                var pipeline = c.Get<IPipeline>();
                
                return new PipelineStepRemover(pipeline)
                    .RemoveIncomingStep(s => s.GetType() == typeof(HandleDeferredMessagesStep));
            });
        }
示例#2
0
        /// <summary>
        /// Uses the given <see cref="StandardConfigurer{TService}"/> of <see cref="ITransport"/> to set the number of workers
        /// to zero (effectively disabling message processing) and installs a decorator of <see cref="IBus"/> that prevents
        /// further modification of the number of workers (thus preventing accidentally starting workers when there's no input queue).
        /// </summary>
        public static void ConfigureOneWayClient(StandardConfigurer<ITransport> configurer)
        {
            configurer.Options.NumberOfWorkers = 0;

            configurer.OtherService<IBus>().Decorate(c =>
            {
                configurer.Options.NumberOfWorkers = 0;
                var resolveRealBus = c.Get<IBus>();
                return new OneWayClientBusDecorator(resolveRealBus);
            }, description: OneWayDecoratorDescription);
        } 
        static void Configure(StandardConfigurer<ITransport> configurer, string connectionString, string tableName, string inputQueueName)
        {
            configurer.Register(context =>
            {
                var connectionProvider = new DbConnectionProvider(connectionString);
                var transport = new SqlServerTransport(connectionProvider, tableName, inputQueueName);
                transport.EnsureTableIsCreated();
                return transport;
            });

            configurer.OtherService<ITimeoutManager>().Register(c => new DisabledTimeoutManager());

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

                return new PipelineStepRemover(pipeline)
                    .RemoveIncomingStep(s => s.GetType() == typeof (HandleDeferredMessagesStep));
            });
        }
        /// <summary>
        /// Configures Rebus to use in-mem message queues, delivering/receiving from the specified <see cref="InMemNetwork"/>
        /// </summary>
        public static void UseInMemoryTransport(this StandardConfigurer <ITransport> configurer, InMemNetwork network, string inputQueueName)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }
            if (network == null)
            {
                throw new ArgumentNullException(nameof(network));
            }
            if (inputQueueName == null)
            {
                throw new ArgumentNullException(nameof(inputQueueName));
            }

            configurer.OtherService <InMemTransport>()
            .Register(context => new InMemTransport(network, inputQueueName));

            configurer.OtherService <ITransportInspector>()
            .Register(context => context.Get <InMemTransport>());

            configurer.Register(context => context.Get <InMemTransport>());
        }
示例#5
0
        /// <summary>Configures Rebus to use Apache Kafka to transport messages as a one-way client (i.e. will not be able to receive any messages).
        /// Performs a simplified configuration of the parameters of the producer used in this transport.</summary>
        /// <param name="configurer"></param>
        /// <param name="brokerList">Initial list of brokers as a CSV list of broker host or host:port.</param>
        public static void UseKafkaAsOneWayClient(this StandardConfigurer <ITransport> configurer, string brokerList)
        {
            // Register implementation of the transport as ISubscriptionStorage as well
            configurer
            .OtherService <KafkaTransport>()
            .Register(c =>
            {
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                var asyncTaskFactory   = c.Get <IAsyncTaskFactory>();
                var cancellationToken  = c.Get <CancellationToken>();
                return(new KafkaTransport(rebusLoggerFactory, asyncTaskFactory
                                          , brokerList, null, null, cancellationToken));
            });

            // Register implementation of the Transport as ITransport
            configurer.Register(c => c.Get <KafkaTransport>());

            // Link the ISubscriberStorage to the transport
            configurer
            .OtherService <ISubscriptionStorage>()
            .Register(c => c.Get <KafkaTransport>(), description: AsbSubStorageText);

            OneWayClientBackdoor.ConfigureOneWayClient(configurer);
        }
示例#6
0
        /// <summary>
        /// Configures Rebus to use RabbitMQ to transport messages as a one-way client (i.e. will not be able to receive any messages)
        /// </summary>
        public static RabbitMqOptionsBuilder UseRabbitMqAsOneWayClient(this StandardConfigurer <ITransport> configurer, string connectionString)
        {
            var options = new RabbitMqOptionsBuilder();

            configurer
            .OtherService <RabbitMqTransport>()
            .Register(c =>
            {
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
                var transport          = new RabbitMqTransport(connectionString, null, rebusLoggerFactory);
                options.Configure(transport);
                return(transport);
            });

            configurer
            .OtherService <ISubscriptionStorage>()
            .Register(c => c.Get <RabbitMqTransport>(), description: RabbitMqSubText);

            configurer.Register(c => c.Get <RabbitMqTransport>());

            OneWayClientBackdoor.ConfigureOneWayClient(configurer);

            return(options);
        }
示例#7
0
        /// <summary>
        /// Installs a message type name convention that can be customized by making further calls to the builder returned from this method.
        /// This can be used to improve interoperability of messages, as e.g.
        /// <code>
        /// Configure.With(...)
        ///     .(...)
        ///     .Serialization(s => {
        ///         s.UseCustomMessageTypeNames()
        ///             .AddWithCustomName&lt;SomeType&gt;("SomeType");
        ///     })
        ///     .Start();
        /// </code>
        /// This will make Rebus put the type name "SomeType" in the <see cref="Headers.Type"/> header, thus removing all of the .NET-specific
        /// stuff like namespace and assembly information.
        /// </summary>
        public static CustomTypeNameConventionBuilder UseCustomMessageTypeNames(this StandardConfigurer <ISerializer> configurer)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            var builder = new CustomTypeNameConventionBuilder();

            configurer
            .OtherService <IMessageTypeNameConvention>()
            .Register(c => builder.GetConvention());

            return(builder);
        }
示例#8
0
        /// <summary>
        /// Adds the given routing function - should return <see cref="ForwardAction.None"/> to do nothing, or another action
        /// available on <see cref="ForwardAction"/> in order to do something to the message
        /// </summary>
        public static void AddTransportMessageForwarder(this StandardConfigurer <IRouter> configurer, Func <TransportMessage, Task <ForwardAction> > routingFunction)
        {
            configurer.OtherService <IPipeline>()
            .Decorate(c =>
            {
                var pipeline           = c.Get <IPipeline>();
                var transport          = c.Get <ITransport>();
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();

                var stepToAdd = new ForwardTransportMessageStep(routingFunction, transport, rebusLoggerFactory);

                return(new PipelineStepConcatenator(pipeline)
                       .OnReceive(stepToAdd, PipelineAbsolutePosition.Front));
            });
        }
        /// <summary>
        /// Sets maximum number of times conflict resolution is invoked. Only relevant in cases where <see cref="Saga{T}.ResolveConflict"/> is implemented in a
        /// saga handler. If the value is set to 0, conflict resolution is disabled even though the <see cref="Saga{T}.ResolveConflict"/> is implemented.
        /// </summary>
        public static void SetMaxConflictResolutionAttempts([NotNull] this StandardConfigurer <ISagaStorage> configurer, int value)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }
            if (value < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(value), value, "Please specify a value greater than or equal to 0");
            }

            configurer.OtherService <Options>().Decorate(c =>
            {
                var options = c.Get <Options>();
                options.MaxConflictResolutionAttempts = value;
                return(options);
            });
        }
        /// <summary>
        /// Forces exclusive using a lockhandler defined by <see cref="IExclusiveSagaAccessLock"/>
        /// </summary>
        public static void EnforceExclusiveAccess(this StandardConfigurer <ISagaStorage> configurer, IExclusiveSagaAccessLock locker)
        {
            if (configurer == null)
            {
                throw new ArgumentNullException(nameof(configurer));
            }

            configurer
            .OtherService <IPipeline>()
            .Decorate(c =>
            {
                var pipeline          = c.Get <IPipeline>();
                var cancellationToken = c.Get <CancellationToken>();
                var step = new EnforceExclusiveSagaAccessIncomingStep(locker, cancellationToken);

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.Before, typeof(LoadSagaDataStep)));
            });
        }
    /// <summary>
    /// Forces exclusive access using a lockhandler defined by <see cref="IExclusiveAccessLock"/>, materialized via a callback within the resolution context
    /// </summary>
    public static void EnforceExclusiveAccess(this StandardConfigurer <ISagaStorage> configurer, Func <IResolutionContext, IExclusiveAccessLock> getLocker, string lockPrefix = null, int maxLockBuckets = 1000)
    {
        if (configurer == null)
        {
            throw new ArgumentNullException(nameof(configurer));
        }

        configurer
        .OtherService <IPipeline>()
        .Decorate(c =>
        {
            var pipeline          = c.Get <IPipeline>();
            var cancellationToken = c.Get <CancellationToken>();
            var step = new EnforceExclusiveSagaAccessIncomingStep(getLocker(c), maxLockBuckets, lockPrefix ?? "sagalock_", cancellationToken);

            return(new PipelineStepInjector(pipeline)
                   .OnReceive(step, PipelineRelativePosition.Before, typeof(LoadSagaDataStep)));
        });
    }
示例#12
0
        /// <summary>
        /// <para>
        /// Configures Rebus to automatically transfer message bodies as data bus attachments, if the size of the body exceeds <paramref name="bodySizeThresholdBytes"/> bytes.
        /// </para>
        /// <para>
        /// This can be used in situations when you know that the message size will sometimes be too big for the transport, like e.g. when using Azure Service Bus.
        /// With Azure Service Bus (at least at the time of writing), the maximum message size is 256 kB, including all headers and everything.
        /// </para>
        /// <para>
        /// Since it can be hard to predict how large the final Azure Service Bus transport message can get, if you know that your message payloads will approach the 256 kB limit,
        /// it is recommended to enable automatic compression of message payloads (by calling <see cref="ZipConfigurationExtensions.EnableCompression"/>).
        /// </para>
        /// <para>
        /// If you still fear that your message payloads will approach the limit, this feature is for you :) simply ensure that the data bus is properly configured
        /// (e.g. to use Azure Blob Storage to store attachments), and then call this method to enable automatic big message claim check.
        /// </para>
        /// </summary>
        public static void SendBigMessagesAsAttachments(this StandardConfigurer <IDataBusStorage> configurer, int bodySizeThresholdBytes)
        {
            configurer
            .OtherService <IPipeline>()
            .Decorate(c =>
            {
                var pipeline = c.Get <IPipeline>();
                var dataBus  = c.Get <IDataBus>();

                var dehydrateStep = new DehydrateOutgoingMessageStep(dataBus, bodySizeThresholdBytes);

                return(new PipelineStepInjector(pipeline)
                       .OnSend(
                           step: dehydrateStep,
                           position: PipelineRelativePosition.After,
                           anchorStep: typeof(SerializeOutgoingMessageStep)
                           ));
            });
        }
示例#13
0
    /// <summary>
    /// Adds the given routing function - should return <see cref="ForwardAction.None"/> to do nothing, or another action
    /// available on <see cref="ForwardAction"/> in order to do something to the message
    /// </summary>
    public static void AddTransportMessageForwarder(this StandardConfigurer <IRouter> configurer,
                                                    Func <TransportMessage, Task <ForwardAction> > routingFunction,
                                                    ErrorBehavior errorBehavior)
    {
        configurer.OtherService <IPipeline>()
        .Decorate(c =>
        {
            var pipeline           = c.Get <IPipeline>();
            var transport          = c.Get <ITransport>();
            var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();

            var errorQueueName = c.Has <SimpleRetryStrategySettings>()
                    ? c.Get <SimpleRetryStrategySettings>().ErrorQueueAddress
                    : "error";

            var stepToAdd = new ForwardTransportMessageStep(routingFunction, transport, rebusLoggerFactory, errorQueueName, errorBehavior);

            return(new PipelineStepConcatenator(pipeline)
                   .OnReceive(stepToAdd, PipelineAbsolutePosition.Front));
        });
    }
        /// <summary>
        /// Short-circuits the usual retry strategy by immediately forwarding the transport message to the specified queue when an
        /// exception of the type specified by <typeparamref name="TException"/> is caught. Please note that any outgoing message
        /// that have already been sent WILL BE SENT because the queue transaction is not rolled back.
        /// Use <paramref name="logLevel"/> to specify which log level to use when logging the forwarding action.
        /// </summary>
        public static StandardConfigurer <IRouter> ForwardOnException <TException>(this StandardConfigurer <IRouter> configurer, string destinationQueue, LogLevel logLevel, Func <TException, bool> shouldForward = null)
            where TException : Exception
        {
            configurer
            .OtherService <IPipeline>()
            .Decorate(c =>
            {
                var pipeline           = c.Get <IPipeline>();
                var transport          = c.Get <ITransport>();
                var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();

                var shouldForwardException = shouldForward != null
                        ? (Func <Exception, bool>)(exception => shouldForward((TException)exception))
                        : (exception => true);

                var step = new ForwardOnExceptionsStep(typeof(TException), destinationQueue, transport, rebusLoggerFactory, logLevel, shouldForwardException);

                return(new PipelineStepInjector(pipeline)
                       .OnReceive(step, PipelineRelativePosition.After, typeof(SimpleRetryStrategyStep)));
            });

            return(configurer);
        }
示例#15
0
    /// <summary>
    /// Uses the given <see cref="StandardConfigurer{TService}"/> of <see cref="ITransport"/> to set the number of workers
    /// to zero (effectively disabling message processing) and installs a decorator of <see cref="IBus"/> that prevents
    /// further modification of the number of workers (thus preventing accidentally starting workers when there's no input queue).
    /// </summary>
    public static void ConfigureOneWayClient(StandardConfigurer <ITransport> configurer)
    {
        configurer.Options.NumberOfWorkers = 0;

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

            if (transport.Address != null)
            {
                throw new InvalidOperationException($"Cannot configure this bus to be a one-way client, because the transport is configured with '{transport.Address}' as its input queue. One-way clients must have a NULL input queue, otherwise the transport could be fooled into believing it was supposed to receive messages");
            }

            var options             = c.Get <Options>();
            options.NumberOfWorkers = 0;

            var realBus            = c.Get <IBus>();
            var rebusLoggerFactory = c.Get <IRebusLoggerFactory>();
            var busDecorator       = new OneWayClientBusDecorator(realBus, rebusLoggerFactory);

            return(busDecorator);
        }, description: OneWayDecoratorDescription);
    }
示例#16
0
    static TTransportOptions Configure <TTransportOptions>(StandardConfigurer <ITransport> configurer, TransportFactoryDelegate transportFactory, TTransportOptions transportOptions) where TTransportOptions : SqlServerTransportOptions
    {
        configurer.Register(context =>
        {
            if (transportOptions.IsOneWayClient)
            {
                OneWayClientBackdoor.ConfigureOneWayClient(configurer);
            }

            var connectionProvider = transportOptions.ConnectionProviderFactory(context);
            var transport          = transportFactory(context, connectionProvider, transportOptions.InputQueueName);
            if ((transportOptions.InputQueueName != null) && (transportOptions.EnsureTablesAreCreated == true))
            {
                transport.EnsureTableIsCreated();
            }

            return(transport);
        }
                            );

        configurer.OtherService <Options>().Decorate(c =>
        {
            var options = c.Get <Options>();

            // if the transport is a one-way client and no external timeout manager has been configured, set the
            // external timeout manager's address to this magic string, which we'll detect later on
            if (transportOptions.IsOneWayClient && string.IsNullOrWhiteSpace(options.ExternalTimeoutManagerAddressOrNull))
            {
                options.ExternalTimeoutManagerAddressOrNull = SqlServerTransport.MagicExternalTimeoutManagerAddress;
            }

            return(options);
        });

        return(transportOptions);
    }
示例#17
0
 public RebusOutboxProcessorConfigurer OutboxContextFactory(Action <StandardConfigurer <IOutboxContextFactory> > configurer)
 {
     configurer?.Invoke(_configurer.OtherService <IOutboxContextFactory>());
     return(this);
 }
        static void Register(StandardConfigurer<ITransport> configurer, string inputQueueAddress, CloudStorageAccount storageAccount)
        {
            if (configurer == null) throw new ArgumentNullException(nameof(configurer));
            if (inputQueueAddress == null) throw new ArgumentNullException(nameof(inputQueueAddress));
            if (storageAccount == null) throw new ArgumentNullException(nameof(storageAccount));

            configurer.Register(c =>
            {
                var rebusLoggerFactory = c.Get<IRebusLoggerFactory>();
                return new AzureStorageQueuesTransport(storageAccount, inputQueueAddress, rebusLoggerFactory);
            });

            configurer.OtherService<ITimeoutManager>().Register(c => new DisabledTimeoutManager(), description: AsqTimeoutManagerText);

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

                return new PipelineStepRemover(pipeline)
                    .RemoveIncomingStep(s => s.GetType() == typeof(HandleDeferredMessagesStep));
            });
        }