public static ISagaConfigurator <TS, TD> UseRabbitMQTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var sagaType           = typeof(TS);
            var messageHandlerType = typeof(IHandleMessage <>).GetGenericTypeDefinition();
            var interfaces         = sagaType.GetInterfaces();

            foreach (var i in interfaces)
            {
                if (!i.IsGenericType)
                {
                    continue;
                }

                var openGeneric = i.GetGenericTypeDefinition();
                if (!openGeneric.IsAssignableFrom(messageHandlerType))
                {
                    continue;
                }

                var messageType = i.GetGenericArguments().First();

                sagaConfigurator.Services.AddSingleton(typeof(ISubscriber),
                                                       typeof(RabbitSubscriber <>).MakeGenericType(messageType));
            }

            return(sagaConfigurator);
        }
예제 #2
0
        public static ISagaConfigurator <TS, TD> UseInMemoryTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var sagaType           = typeof(TS);
            var messageHandlerType = typeof(IHandleMessage <>).GetGenericTypeDefinition();
            var interfaces         = sagaType.GetInterfaces();

            foreach (var i in interfaces)
            {
                if (!i.IsGenericType)
                {
                    continue;
                }

                var openGeneric = i.GetGenericTypeDefinition();
                if (!openGeneric.IsAssignableFrom(messageHandlerType))
                {
                    continue;
                }

                var messageType = i.GetGenericArguments().First();

                var registerMessageMethod = RawRegisterMessageMethod.MakeGenericMethod(messageType);
                registerMessageMethod.Invoke(null, new[] { sagaConfigurator.Services });
            }

            return(sagaConfigurator);
        }
예제 #3
0
 public MessageRetrySagaConfigurationObserver(ISagaConfigurator <TSaga> configurator, CancellationToken cancellationToken,
                                              Action <IRetryConfigurator> configure)
 {
     _configurator      = configurator;
     _cancellationToken = cancellationToken;
     _configure         = configure;
 }
        public static ISagaConfigurator <TS, TD> UseRabbitMQTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator,
                                                                               RabbitConfiguration config)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var sagaType           = typeof(TS);
            var messageHandlerType = typeof(IHandleMessage <>).GetGenericTypeDefinition();
            var interfaces         = sagaType.GetInterfaces();

            foreach (var i in interfaces)
            {
                if (!i.IsGenericType)
                {
                    continue;
                }

                var openGeneric = i.GetGenericTypeDefinition();
                if (!openGeneric.IsAssignableFrom(messageHandlerType))
                {
                    continue;
                }

                var messageType = i.GetGenericArguments().First();

                sagaConfigurator.Services.AddSingleton(typeof(ISubscriber),
                                                       typeof(RabbitSubscriber <>).MakeGenericType(messageType));
            }

            if (!_initialized)
            {
                var encoder = new JsonEncoder();
                sagaConfigurator.Services.AddSingleton <IEncoder>(encoder);
                sagaConfigurator.Services.AddSingleton <IDecoder>(encoder);

                sagaConfigurator.Services.AddSingleton <IQueueReferenceFactory, QueueReferenceFactory>();
                sagaConfigurator.Services.AddSingleton <IMessageParser, MessageParser>();
                sagaConfigurator.Services.AddSingleton <IPublisher, RabbitPublisher>();
                sagaConfigurator.Services.AddSingleton <IPublisherChannelFactory, PublisherChannelFactory>();

                sagaConfigurator.Services.AddSingleton <IConnectionFactory>(ctx =>
                {
                    var connectionFactory = new ConnectionFactory()
                    {
                        HostName = config.HostName,
                        UserName = config.UserName,
                        Password = config.Password,
                        Port     = AmqpTcpEndpoint.UseDefaultPort,
                        DispatchConsumersAsync = true
                    };
                    return(connectionFactory);
                });

                sagaConfigurator.Services.AddSingleton <IBusConnection, RabbitPersistentConnection>();

                _initialized = true;
            }

            return(sagaConfigurator);
        }
예제 #5
0
        protected override void ConfigureSaga(IReceiveEndpointConfigurator endpointConfigurator,
                                              ISagaConfigurator <AllocationState> sagaConfigurator)
        {
            // to resolve the duplicate key error, AllocationCreated, ReleaseRequested
            endpointConfigurator.UseMessageRetry(configurator => configurator.Interval(3, 1000));

            // this holds the messages until the persistence part of those messages completed
            endpointConfigurator.UseInMemoryOutbox();
        }
예제 #6
0
        public static ISagaConfigurator <TS, TD> UseInMemoryPersistence <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            sagaConfigurator.Services.AddSingleton(typeof(ISagaStateRepository), typeof(InMemorySagaStateRepository));
            sagaConfigurator.Services.AddSingleton <IUnitOfWork, InMemoryUnitOfWork>();

            return(sagaConfigurator);
        }
예제 #7
0
        protected override void ConfigureSaga(IReceiveEndpointConfigurator endpointConfigurator,
                                              ISagaConfigurator <OrderState> sagaConfigurator)
        {
            // var partition = endpointConfigurator.CreatePartitioner(8);
            // sagaConfigurator.Message<OrderSubmitted>(m => m.UsePartitioner(partition, m => m.Message.CustomerNumber));

            endpointConfigurator.UseMessageRetry(r => r.Intervals(500, 5000, 10000));
            endpointConfigurator.UseInMemoryOutbox();
        }
예제 #8
0
        public void StateMachineSagaConfigured <TInstance>(ISagaConfigurator <TInstance> configurator, SagaStateMachine <TInstance> stateMachine)
            where TInstance : class, ISaga, SagaStateMachineInstance
        {
            All(observer =>
            {
                observer.StateMachineSagaConfigured(configurator, stateMachine);

                return(true);
            });
        }
예제 #9
0
        public void SagaConfigured <TSaga>(ISagaConfigurator <TSaga> configurator)
            where TSaga : class, ISaga
        {
            All(observer =>
            {
                observer.SagaConfigured(configurator);

                return(true);
            });
        }
예제 #10
0
        /// <summary>
        /// Includes an outbox in the consume filter path, which delays outgoing messages until the return path
        /// of the pipeline returns to the outbox filter. At this point, the message execution pipeline should be
        /// nearly complete with only the ack remaining. If an exception is thrown, the messages are not sent/published.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="configure">Configure the outbox</param>
        public static void UseInMemoryOutbox <TSaga>(this ISagaConfigurator <TSaga> configurator, Action <IOutboxConfigurator> configure = default)
            where TSaga : class, ISaga
        {
            if (configurator == null)
            {
                throw new ArgumentNullException(nameof(configurator));
            }

            var observer = new InMemoryOutboxSagaConfigurationObserver <TSaga>(configurator, configure);

            configurator.ConnectSagaConfigurationObserver(observer);
        }
        /// <summary>
        /// Limits the number of concurrent messages consumed by the saga, regardless of message type.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="concurrentMessageLimit">The concurrent message limit for all message types for the saga</param>
        public static void UseConcurrentMessageLimit <TSaga>(this ISagaConfigurator <TSaga> configurator, int concurrentMessageLimit)
            where TSaga : class, ISaga
        {
            if (configurator == null)
            {
                throw new ArgumentNullException(nameof(configurator));
            }

            var observer = new ConcurrencyLimitSagaConfigurationObserver <TSaga>(configurator, concurrentMessageLimit);

            configurator.ConnectSagaConfigurationObserver(observer);
        }
        /// <summary>
        /// Configure scheduled redelivery for the saga, regardless of message type.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="configure"></param>
        public static void UseScheduledRedelivery <TSaga>(this ISagaConfigurator <TSaga> configurator, Action <IRetryConfigurator> configure)
            where TSaga : class, ISaga
        {
            if (configurator == null)
            {
                throw new ArgumentNullException(nameof(configurator));
            }

            var observer = new MessageRedeliverySagaConfigurationObserver <TSaga>(configurator, configure);

            configurator.ConnectSagaConfigurationObserver(observer);
        }
        public static ISagaConfigurator <TS, TD> UseInMemoryTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var messageTypes = SagaUtils <TS, TD> .GetHandledMessageTypes();

            foreach (var messageType in messageTypes)
            {
                var registerMessageMethod = RawRegisterMessageMethod.MakeGenericMethod(messageType);
                registerMessageMethod.Invoke(null, new[] { sagaConfigurator.Services });
            }

            return(sagaConfigurator);
        }
        public static ISagaConfigurator <TS, TD> UseRabbitMQTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var messageTypes = SagaUtils <TS, TD> .GetHandledMessageTypes();

            foreach (var messageType in messageTypes)
            {
                sagaConfigurator.Services.AddBusSubscriber(
                    typeof(RabbitSubscriber <>).MakeGenericType(messageType));
            }

            return(sagaConfigurator);
        }
        public static ISagaConfigurator <TS, TD> UseKafkaTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var messageTypes = typeof(TS).GetHandledMessageTypes();

            foreach (var messageType in messageTypes)
            {
                sagaConfigurator.Services.AddBusSubscriber(
                    typeof(KafkaSubscriber <>).MakeGenericType(messageType));
                sagaConfigurator.Services.AddSingleton(typeof(IInfrastructureCreator),
                                                       typeof(KafkaInfrastructureCreator <>).MakeGenericType(messageType));
            }

            return(sagaConfigurator);
        }
        /// <summary>
        /// Configures the message retry for the consumer consumer, regardless of message type.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="busFactoryConfigurator">
        /// The bus factory configurator, to connect the observer, to cancel retries if the bus is stopped
        /// </param>
        /// <param name="configure"></param>
        public static void UseMessageRetry <TSaga>(this ISagaConfigurator <TSaga> configurator, IBusFactoryConfigurator busFactoryConfigurator,
                                                   Action <IRetryConfigurator> configure)
            where TSaga : class, ISaga
        {
            if (configurator == null)
            {
                throw new ArgumentNullException(nameof(configurator));
            }

            var retryObserver = new RetryBusObserver();

            busFactoryConfigurator.ConnectBusObserver(retryObserver);

            var observer = new MessageRetrySagaConfigurationObserver <TSaga>(configurator, retryObserver.Stopping, configure);

            configurator.ConnectSagaConfigurationObserver(observer);
        }
        /// <summary>
        /// Limits the number of concurrent messages consumed by the saga, regardless of message type.
        /// </summary>
        /// <param name="configurator"></param>
        /// <param name="concurrentMessageLimit">The concurrent message limit for all message types for the saga</param>
        /// <param name="managementEndpointConfigurator">A management endpoint configurator to support runtime adjustment</param>
        /// <param name="id">An identifier for the concurrency limit to allow selective adjustment</param>
        public static void UseConcurrentMessageLimit <TSaga>(this ISagaConfigurator <TSaga> configurator, int concurrentMessageLimit,
                                                             IManagementEndpointConfigurator managementEndpointConfigurator, string id = null)
            where TSaga : class, ISaga
        {
            if (configurator == null)
            {
                throw new ArgumentNullException(nameof(configurator));
            }

            var observer = new ConcurrencyLimitSagaConfigurationObserver <TSaga>(configurator, concurrentMessageLimit, id);

            configurator.ConnectSagaConfigurationObserver(observer);

            managementEndpointConfigurator.Instance(observer.Limiter, x =>
            {
                x.UseConcurrentMessageLimit(1);
                x.Message <SetConcurrencyLimit>(m => m.UseRetry(r => r.None()));
            });
        }
예제 #18
0
        public static ISagaConfigurator <TS, TD> UseInMemoryTransport <TS, TD>(this ISagaConfigurator <TS, TD> sagaConfigurator)
            where TS : Saga <TD>
            where TD : SagaState
        {
            var sagaType           = typeof(TS);
            var messageHandlerType = typeof(IHandleMessage <>).GetGenericTypeDefinition();
            var interfaces         = sagaType.GetInterfaces();

            foreach (var i in interfaces)
            {
                if (!i.IsGenericType)
                {
                    continue;
                }

                var openGeneric = i.GetGenericTypeDefinition();
                if (!openGeneric.IsAssignableFrom(messageHandlerType))
                {
                    continue;
                }

                var messageType = i.GetGenericArguments().First();

                var     rawMethod = typeof(Channel).GetMethod(nameof(Channel.CreateUnbounded), Array.Empty <Type>());
                var     method    = rawMethod.MakeGenericMethod(messageType);
                dynamic channel   = method.Invoke(null, null);

                sagaConfigurator.Services.AddSingleton(typeof(Channel <>).MakeGenericType(messageType), (object)channel);

                sagaConfigurator.Services.AddSingleton(typeof(ChannelWriter <>).MakeGenericType(messageType), (object)channel.Writer);

                sagaConfigurator.Services.AddSingleton(typeof(ChannelReader <>).MakeGenericType(messageType), (object)channel.Reader);

                sagaConfigurator.Services.AddSingleton(typeof(ISubscriber),
                                                       typeof(InMemorySubscriber <>).MakeGenericType(messageType));
            }

            sagaConfigurator.Services.AddSingleton <IPublisher, InMemoryPublisher>()
            .AddSingleton <IChannelFactory, ChannelFactory>();

            return(sagaConfigurator);
        }
예제 #19
0
 public static ISagaConfigurator <TS, TD> UseMongoPersistence <TS, TD>(
     this ISagaConfigurator <TS, TD> sagaConfigurator, MongoConfiguration config)
     where TS : Saga <TD>
     where TD : SagaState
 {
     sagaConfigurator.Services
     .AddSingleton <IMongoClient>(ctx => new MongoClient(connectionString: config.ConnectionString))
     .AddSingleton(ctx =>
     {
         var client   = ctx.GetRequiredService <IMongoClient>();
         var database = client.GetDatabase(config.DbName);
         return(database);
     })
     .AddSingleton <ISerializer, JsonSerializer>()
     .AddSingleton <IDbContext, DbContext>()
     .AddSingleton <IUnitOfWork, MongoUnitOfWork>()
     .AddSingleton(config.RepositoryOptions)
     .AddSingleton <ISagaStateRepository, MongoSagaStateRepository>()
     .AddSingleton <IOutboxRepository, OutboxRepository>();
     return(sagaConfigurator);
 }
예제 #20
0
 public void SagaConfigured <TSaga>(ISagaConfigurator <TSaga> configurator)
     where TSaga : class, ISaga
 {
     _sagaObservers.SagaConfigured(configurator);
 }
 public void StateMachineSagaConfigured <TInstance>(ISagaConfigurator <TInstance> configurator, SagaStateMachine <TInstance> stateMachine)
     where TInstance : class, ISaga, SagaStateMachineInstance
 {
 }
 public void SagaConfigured <T>(ISagaConfigurator <T> configurator)
     where T : class, ISaga
 {
 }
예제 #23
0
 public void SagaConfigured <TSaga>(ISagaConfigurator <TSaga> configurator)
     where TSaga : class, ISaga
 {
     _busEndpointConfiguration.Consume.Configurator.SagaConfigured(configurator);
 }
예제 #24
0
 protected override void ConfigureSagaTransport <TS, TD>(ISagaConfigurator <TS, TD> cfg) =>
 cfg.UseInMemoryTransport();
 protected override void ConfigureSagaTransport <TS, TD>(ISagaConfigurator <TS, TD> cfg) =>
 cfg.UseRabbitMQTransport();
예제 #26
0
 protected override void ConfigureSaga(IReceiveEndpointConfigurator endpointConfigurator, ISagaConfigurator <OrderState> sagaConfigurator)
 {
     endpointConfigurator.UseMessageRetry(r => r.Intervals(500, 5000, 10000));
     endpointConfigurator.UseInMemoryOutbox();
 }
 void ISagaConfigurationObserver.SagaConfigured <TSaga>(ISagaConfigurator <TSaga> configurator)
 {
 }
예제 #28
0
 public void StateMachineSagaConfigured <TInstance>(ISagaConfigurator <TInstance> configurator, SagaStateMachine <TInstance> stateMachine)
     where TInstance : class, ISaga, SagaStateMachineInstance
 {
     _sagaObservers.StateMachineSagaConfigured(configurator, stateMachine);
 }
예제 #29
0
            protected override void ConfigureSaga(IReceiveEndpointConfigurator endpointConfigurator, ISagaConfigurator <DiscoveryPingState> sagaConfigurator)
            {
                var partition = endpointConfigurator.CreatePartitioner(Environment.ProcessorCount);

                sagaConfigurator.Message <PingReceived>(x => x.UsePartitioner(partition, m => m.Message.CorrelationId));
                sagaConfigurator.Message <PingAcknowledged>(x => x.UsePartitioner(partition, m => m.Message.CorrelationId));
            }
예제 #30
0
 public void SagaConfigured <TSaga>(ISagaConfigurator <TSaga> configurator) where TSaga : class, ISaga
 {
     _configurator.SagaConfigured(configurator);
 }