Exemplo n.º 1
0
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor <StorageType.Sagas>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for saga storage. Select another persistence or disable the sagas feature using endpointConfiguration.DisableFeature<Sagas>()");
            }

            var sagaIdGenerator = context.Settings.GetOrDefault <ISagaIdGenerator>() ?? new DefaultSagaIdGenerator();

            var sagaMetaModel = context.Settings.Get <SagaMetadataCollection>();

            sagaMetaModel.Initialize(context.Settings.GetAvailableTypes(), conventions);

            var verifyIfEntitiesAreShared = !context.Settings.GetOrDefault <bool>(SagaSettings.DisableVerifyingIfEntitiesAreShared);

            if (verifyIfEntitiesAreShared)
            {
                sagaMetaModel.VerifyIfEntitiesAreShared();
            }

            RegisterCustomFindersInContainer(context.Container, sagaMetaModel);

            foreach (var t in context.Settings.GetAvailableTypes())
            {
                if (IsSagaNotFoundHandler(t))
                {
                    context.Container.ConfigureComponent(t, DependencyLifecycle.InstancePerCall);
                }
            }

            // Register the Saga related behaviors for incoming messages
            context.Pipeline.Register("InvokeSaga", b => new SagaPersistenceBehavior(b.GetRequiredService <ISagaPersister>(), sagaIdGenerator, sagaMetaModel), "Invokes the saga logic");
            context.Pipeline.Register("InvokeSagaNotFound", new InvokeSagaNotFoundBehavior(), "Invokes saga not found logic");
            context.Pipeline.Register("AttachSagaDetailsToOutGoingMessage", new AttachSagaDetailsToOutGoingMessageBehavior(), "Makes sure that outgoing messages have saga info attached to them");
        }
Exemplo n.º 2
0
        public void Should_return_false_when_checking_if_persistence_supports_storage_type()
        {
            var settings = new SettingsHolder();

            var supported = PersistenceStartup.HasSupportFor <StorageType.Subscriptions>(settings);

            Assert.IsFalse(supported);
        }
Exemplo n.º 3
0
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor <StorageType.Outbox>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for outbox storage. Select another persistence or disable the outbox feature using endpointConfiguration.DisableFeature<Outbox>()");
            }

            //note: in the future we should change the persister api to give us a "outbox factory" so that we can register it in DI here instead of relying on the persister to do it
            context.Pipeline.Register("ForceBatchDispatchToBeIsolated", new ForceBatchDispatchToBeIsolatedBehavior(), "Makes sure that we dispatch straight to the transport so that we can safely set the outbox record to dispatched one the dispatch pipeline returns.");
        }
Exemplo n.º 4
0
        public void Should_prevent_using_different_persistence_for_sagas_and_outbox()
        {
            var config = new EndpointConfiguration("MyEndpoint");

            config.UsePersistence <FakeSagaPersistence, StorageType.Sagas>();
            config.UsePersistence <FakeOutboxPersistence, StorageType.Outbox>();

            var startup = new PersistenceStartup();

            Assert.Throws <Exception>(() =>
            {
                startup.Run(config.Settings);
            }, "Sagas and Outbox need to use the same type of persistence. Saga is configured to use FakeSagaPersistence. Outbox is configured to use FakeOutboxPersistence");
        }
Exemplo n.º 5
0
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor <StorageType.Timeouts>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for timeout storage. Select another persistence or disable the timeout manager feature using endpointConfiguration.DisableFeature<TimeoutManager>()");
            }

            var pushRuntimeSettings = context.Settings.GetTimeoutManagerMaxConcurrency();

            SetupStorageSatellite(context, pushRuntimeSettings);

            var dispatcherAddress = SetupDispatcherSatellite(context, pushRuntimeSettings);

            SetupTimeoutPoller(context, dispatcherAddress);
        }
Exemplo n.º 6
0
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            // The MessageDrivenSubscriptions feature needs to be activated when using the subscription migration mode as some persister packages check this feature before enabling the subscription storage.
            if (SubscriptionMigrationMode.IsMigrationModeEnabled(context.Settings))
            {
                return;
            }

            if (!PersistenceStartup.HasSupportFor <StorageType.Subscriptions>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for subscription storage. Select another persistence or disable the message-driven subscriptions feature using endpointConfiguration.DisableFeature<MessageDrivenSubscriptions>()");
            }

            var transportInfrastructure = context.Settings.Get <TransportInfrastructure>();
            var canReceive           = !context.Settings.GetOrDefault <bool>("Endpoint.SendOnly");
            var conventions          = context.Settings.Get <Conventions>();
            var enforceBestPractices = context.Routing.EnforceBestPractices;

            var distributionPolicy   = context.Routing.DistributionPolicy;
            var endpointInstances    = context.Routing.EndpointInstances;
            var publishers           = context.Routing.Publishers;
            var configuredPublishers = context.Settings.Get <ConfiguredPublishers>();

            configuredPublishers.Apply(publishers, conventions, enforceBestPractices);

            context.Pipeline.Register(b =>
            {
                var unicastPublishRouter = new UnicastPublishRouter(b.Build <MessageMetadataRegistry>(), i => transportInfrastructure.ToTransportAddress(LogicalAddress.CreateRemoteAddress(i)), b.Build <ISubscriptionStorage>());
                return(new UnicastPublishRouterConnector(unicastPublishRouter, distributionPolicy));
            }, "Determines how the published messages should be routed");

            if (canReceive)
            {
                var subscriberAddress  = context.Receiving.LocalAddress;
                var subscriptionRouter = new SubscriptionRouter(publishers, endpointInstances, i => transportInfrastructure.ToTransportAddress(LogicalAddress.CreateRemoteAddress(i)));

                context.Pipeline.Register(b => new MessageDrivenSubscribeTerminator(subscriptionRouter, subscriberAddress, context.Settings.EndpointName(), b.Build <IDispatchMessages>()), "Sends subscription requests when message driven subscriptions is in use");
                context.Pipeline.Register(b => new MessageDrivenUnsubscribeTerminator(subscriptionRouter, subscriberAddress, context.Settings.EndpointName(), b.Build <IDispatchMessages>()), "Sends requests to unsubscribe when message driven subscriptions is in use");

                var authorizer = context.Settings.GetSubscriptionAuthorizer();
                if (authorizer == null)
                {
                    authorizer = _ => true;
                }
                context.Container.RegisterSingleton(authorizer);
                context.Pipeline.Register <SubscriptionReceiverBehavior.Registration>();
            }
        }
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor <StorageType.Subscriptions>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for subscription storage. Select another persistence or disable the message-driven subscriptions feature using endpointConfiguration.DisableFeature<MessageDrivenSubscriptions>()");
            }

            context.Pipeline.Register <SubscriptionReceiverBehavior.Registration>();
            var authorizer = context.Settings.GetSubscriptionAuthorizer();

            if (authorizer == null)
            {
                authorizer = _ => true;
            }
            context.Container.RegisterSingleton(authorizer);
        }
Exemplo n.º 8
0
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor <StorageType.Outbox>(context.Settings))
            {
                throw new Exception("The selected persistence doesn't have support for outbox storage. Select another persistence or disable the outbox feature using endpointConfiguration.DisableFeature<Outbox>()");
            }

            if (context.Settings.GetRequiredTransactionModeForReceives() != TransportTransactionMode.ReceiveOnly)
            {
                throw new Exception(
                          $"Outbox requires transport to be running in ${nameof(TransportTransactionMode.ReceiveOnly)} mode. Use ${nameof(TransportDefinition.TransportTransactionMode)} property on the transport definition to specify the transaction mode.");
            }

            //note: in the future we should change the persister api to give us a "outbox factory" so that we can register it in DI here instead of relying on the persister to do it
            context.Pipeline.Register("ForceBatchDispatchToBeIsolated", new ForceBatchDispatchToBeIsolatedBehavior(), "Makes sure that we dispatch straight to the transport so that we can safely set the outbox record to dispatched one the dispatch pipeline returns.");
        }
Exemplo n.º 9
0
        /// <summary>
        /// See <see cref="Feature.Setup"/>
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            if (!PersistenceStartup.HasSupportFor(context.Settings, Storage.Outbox))
            {
                throw new Exception("Selected persister doesn't have support for outbox storage. Please select another storage or disable the outbox feature using config.Features(f=>f.Disable<Outbox>())");
            }

            context.Pipeline.Register <OutboxDeduplicationBehavior.OutboxDeduplicationRegistration>();
            context.Pipeline.Register <OutboxRecordBehavior.OutboxRecorderRegistration>();
            context.Pipeline.Replace(WellKnownStep.DispatchMessageToTransport, typeof(OutboxSendBehavior), "Sending behavior with a delay sending until all business transactions are committed to the outbox storage");

            context.Container.ConfigureComponent <OutboxDeduplicationBehavior>(DependencyLifecycle.InstancePerCall)
            .ConfigureProperty(t => t.TransactionSettings, new TransactionSettings(context.Settings));

            //make the audit use the outbox as well
            context.Container.ConfigureComponent <OutboxAwareAuditer>(DependencyLifecycle.InstancePerCall);
            context.Container.ConfigureProperty <AuditerWrapper>(t => t.AuditerImplType, typeof(OutboxAwareAuditer));
        }
        public void Should_not_prevent_using_different_persistence_for_sagas_and_outbox_if_only_one_of_the_features_is_enabled(bool sagasEnabled, bool outboxEnabled)
        {
            var config = new EndpointConfiguration("MyEndpoint");

            config.UsePersistence <FakeSagaPersistence, StorageType.Sagas>();
            config.UsePersistence <FakeOutboxPersistence, StorageType.Outbox>();

            if (sagasEnabled)
            {
                config.EnableFeature <Sagas>();
            }

            if (outboxEnabled)
            {
                config.EnableFeature <Outbox>();
            }

            var startup = new PersistenceStartup();

            Assert.DoesNotThrow(() => startup.Run(config.Settings), "Should not throw for a single single feature enabled out of the two.");
        }
        /// <summary>
        /// See <see cref="Feature.Setup" />.
        /// </summary>
        protected internal override void Setup(FeatureConfigurationContext context)
        {
            // The MessageDrivenSubscriptions feature needs to be activated when using the subscription migration mode as some persister packages check this feature before enabling the subscription storage.
            if (SubscriptionMigrationMode.IsMigrationModeEnabled(context.Settings))
            {
                return;
            }

            var transportDefinition  = context.Settings.Get <TransportDefinition>();
            var conventions          = context.Settings.Get <Conventions>();
            var enforceBestPractices = context.Routing.EnforceBestPractices;

            var distributionPolicy = context.Routing.DistributionPolicy;
            var endpointInstances  = context.Routing.EndpointInstances;
            var publishers         = context.Routing.Publishers;

            var configuredPublishers = context.Settings.Get <ConfiguredPublishers>();

            configuredPublishers.Apply(publishers, conventions, enforceBestPractices);

            var publishingEnabled = context.Settings.Get <bool>(EnablePublishingSettingsKey);

            if (publishingEnabled)
            {
                if (!PersistenceStartup.HasSupportFor <StorageType.Subscriptions>(context.Settings))
                {
                    throw new Exception("The selected persistence doesn't have support for subscription storage. Select another persistence or disable the publish functionality using transportConfiguration.DisablePublishing()");
                }

                context.Pipeline.Register("UnicastPublishRouterConnector", b =>
                {
                    var unicastPublishRouter = new UnicastPublishRouter(b.GetRequiredService <MessageMetadataRegistry>(), i => transportDefinition.ToTransportAddress(new QueueAddress(i.Endpoint, i.Discriminator, i.Properties, null)), b.GetRequiredService <ISubscriptionStorage>());
                    return(new UnicastPublishConnector(unicastPublishRouter, distributionPolicy));
                }, "Determines how the published messages should be routed");

                var authorizer = context.Settings.GetSubscriptionAuthorizer();
                if (authorizer == null)
                {
                    authorizer = _ => true;
                }
                context.Container.AddSingleton(authorizer);
                context.Pipeline.Register(typeof(SubscriptionReceiverBehavior), "Check for subscription messages and execute the requested behavior to subscribe or unsubscribe.");
            }
            else
            {
                context.Pipeline.Register(typeof(DisabledPublishingTerminator), "Throws an exception when trying to publish with publishing disabled");
            }

            var canReceive = !context.Settings.GetOrDefault <bool>("Endpoint.SendOnly");

            if (canReceive)
            {
                var subscriberAddress  = context.Receiving.LocalAddress;
                var subscriptionRouter = new SubscriptionRouter(publishers, endpointInstances, i => transportDefinition.ToTransportAddress(new QueueAddress(i.Endpoint, i.Discriminator, i.Properties, null)));

                context.Pipeline.Register(b => new MessageDrivenSubscribeTerminator(subscriptionRouter, subscriberAddress, context.Settings.EndpointName(), b.GetRequiredService <IMessageDispatcher>()), "Sends subscription requests when message driven subscriptions is in use");
                context.Pipeline.Register(b => new MessageDrivenUnsubscribeTerminator(subscriptionRouter, subscriberAddress, context.Settings.EndpointName(), b.GetRequiredService <IMessageDispatcher>()), "Sends requests to unsubscribe when message driven subscriptions is in use");
            }
            else
            {
                context.Pipeline.Register(new SendOnlySubscribeTerminator(), "Throws an exception when trying to subscribe from a send-only endpoint");
                context.Pipeline.Register(new SendOnlyUnsubscribeTerminator(), "Throws an exception when trying to unsubscribe from a send-only endpoint");
            }

            // implementations of IInitializableSubscriptionStorage are optional and can be provided by persisters.
            context.RegisterStartupTask(b => new InitializableSubscriptionStorage(b.GetService <IInitializableSubscriptionStorage>()));
        }