public OutboxPersister(IConnectionManager connectionManager, string tablePrefix, SqlDialect sqlDialect, int cleanupBatchSize = 10000)
 {
     this.connectionManager = connectionManager;
     this.sqlDialect        = sqlDialect;
     this.cleanupBatchSize  = cleanupBatchSize;
     outboxCommands         = OutboxCommandBuilder.Build(sqlDialect, tablePrefix);
 }
 public OutboxPersister(Func <DbConnection> connectionBuilder, string tablePrefix, SqlDialect sqlDialect, int cleanupBatchSize = 10000)
 {
     this.connectionBuilder = connectionBuilder;
     this.sqlDialect        = sqlDialect;
     this.cleanupBatchSize  = cleanupBatchSize;
     outboxCommands         = OutboxCommandBuilder.Build(tablePrefix, sqlDialect);
 }
 public OutboxPersister(Func <DbConnection> connectionBuilder, string tablePrefix, string schema, SqlVariant sqlVariant, int cleanupBatchSize = 10000)
 {
     this.connectionBuilder = connectionBuilder;
     this.cleanupBatchSize  = cleanupBatchSize;
     outboxCommands         = OutboxCommandBuilder.Build(tablePrefix, schema, sqlVariant);
     commandBuilder         = new CommandBuilder(sqlVariant);
 }
        static OutboxPersister CreateOutboxPersister(IConnectionManager connectionManager, SqlDialect sqlDialect, bool pessimisticMode, bool transactionScopeMode)
        {
            var outboxCommands = OutboxCommandBuilder.Build(sqlDialect, "PersistenceTests_");
            ConcurrencyControlStrategy concurrencyControlStrategy;

            if (pessimisticMode)
            {
                concurrencyControlStrategy = new PessimisticConcurrencyControlStrategy(sqlDialect, outboxCommands);
            }
            else
            {
                concurrencyControlStrategy = new OptimisticConcurrencyControlStrategy(sqlDialect, outboxCommands);
            }

            ISqlOutboxTransaction transactionFactory()
            {
                return(transactionScopeMode
                    ? (ISqlOutboxTransaction) new TransactionScopeSqlOutboxTransaction(concurrencyControlStrategy, connectionManager, IsolationLevel.ReadCommitted)
                    : new AdoNetSqlOutboxTransaction(concurrencyControlStrategy, connectionManager, System.Data.IsolationLevel.ReadCommitted));
            }

            var outboxPersister = new OutboxPersister(connectionManager, sqlDialect, outboxCommands, transactionFactory);

            return(outboxPersister);
        }
Пример #5
0
    public void Write()
    {
        var directory = Path.Combine(TestContext.CurrentContext.TestDirectory, "../../");

        foreach (var variant in Enum.GetValues(typeof(BuildSqlVariant)).Cast <BuildSqlVariant>())
        {
            Write(directory, variant, "TimeoutCreate", TimeoutScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "TimeoutDrop", TimeoutScriptBuilder.BuildDropScript(variant));

            Write(directory, variant, "OutboxCreate", OutboxScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "OutboxDrop", OutboxScriptBuilder.BuildDropScript(variant));

            Write(directory, variant, "SubscriptionCreate", SubscriptionScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "SubscriptionDrop", SubscriptionScriptBuilder.BuildDropScript(variant));

            var sagaDefinition = new SagaDefinition(
                tableSuffix: "OrderSaga",
                name: "OrderSaga",
                correlationProperty: new CorrelationProperty(
                    name: "OrderNumber",
                    type: CorrelationPropertyType.Int),
                transitionalCorrelationProperty: new CorrelationProperty(
                    name: "OrderId",
                    type: CorrelationPropertyType.Guid));
            Write(directory, variant, "SagaCreate", SagaScriptBuilder.BuildCreateScript(sagaDefinition, variant));
            Write(directory, variant, "SagaDrop", SagaScriptBuilder.BuildDropScript(sagaDefinition, variant));
        }
        foreach (var variant in Enum.GetValues(typeof(SqlVariant)).Cast <SqlVariant>())
        {
            var timeoutCommands = TimeoutCommandBuilder.Build(sqlVariant: variant, tablePrefix: "EndpointName");
            Write(directory, variant, "TimeoutAdd", timeoutCommands.Add);
            Write(directory, variant, "TimeoutNext", timeoutCommands.Next);
            Write(directory, variant, "TimeoutRange", timeoutCommands.Range);
            Write(directory, variant, "TimeoutRemoveById", timeoutCommands.RemoveById);
            Write(directory, variant, "TimeoutRemoveBySagaId", timeoutCommands.RemoveBySagaId);
            Write(directory, variant, "TimeoutPeek", timeoutCommands.Peek);

            var outboxCommands = OutboxCommandBuilder.Build(variant, "EndpointName");
            Write(directory, variant, "OutboxCleanup", outboxCommands.Cleanup);
            Write(directory, variant, "OutboxGet", outboxCommands.Get);
            Write(directory, variant, "OutboxSetAsDispatched", outboxCommands.SetAsDispatched);
            Write(directory, variant, "OutboxStore", outboxCommands.Store);

            var subscriptionCommands = SubscriptionCommandBuilder.Build(variant, "EndpointName");
            Write(directory, variant, "SubscriptionSubscribe", subscriptionCommands.Subscribe);
            Write(directory, variant, "SubscriptionUnsubscribe", subscriptionCommands.Unsubscribe);
            Write(directory, variant, "SubscriptionGetSubscribers", subscriptionCommands.GetSubscribers(new List <MessageType>
            {
                new MessageType("MessageTypeName", new Version())
            }));

            var sagaCommandBuilder = new SagaCommandBuilder(variant, "EndpointName");
            Write(directory, variant, "SagaComplete", sagaCommandBuilder.BuildCompleteCommand("SagaName"));
            Write(directory, variant, "SagadGetByProperty", sagaCommandBuilder.BuildGetByPropertyCommand("SagaName", "PropertyName"));
            Write(directory, variant, "SagaGetBySagaId", sagaCommandBuilder.BuildGetBySagaIdCommand("SagaName"));
            Write(directory, variant, "SagaSave", sagaCommandBuilder.BuildSaveCommand("SagaName", "CorrelationPproperty", "TransitionalCorrelationPproperty"));
            Write(directory, variant, "SagaUpdate", sagaCommandBuilder.BuildUpdateCommand("SagaName", "TransitionalCorrelationPproperty"));
        }
    }
    public void Store()
    {
        var timeoutCommands = OutboxCommandBuilder.Build("TheTablePrefix", sqlDialect);

        using (NamerFactory.AsEnvironmentSpecificTest(() => GetType().Name))
        {
            Approvals.Verify(timeoutCommands.Store);
        }
    }
Пример #7
0
    OutboxPersister Setup(string theSchema)
    {
        var dialect        = sqlDialect.Convert(theSchema);
        var outboxCommands = OutboxCommandBuilder.Build(dialect, $"{GetTablePrefix()}_");

        var connectionManager = new ConnectionManager(() => GetConnection()(theSchema));
        var persister         = new OutboxPersister(
            connectionManager: connectionManager,
            sqlDialect: dialect,
            outboxCommands: outboxCommands,
            outboxTransactionFactory: () =>
        {
            ConcurrencyControlStrategy behavior;
            if (pessimistic)
            {
                behavior = new PessimisticConcurrencyControlStrategy(dialect, outboxCommands);
            }
            else
            {
                behavior = new OptimisticConcurrencyControlStrategy(dialect, outboxCommands);
            }

            return(transactionScope
                    ? (ISqlOutboxTransaction) new TransactionScopeSqlOutboxTransaction(behavior, connectionManager, IsolationLevel.ReadCommitted)
                    : new AdoNetSqlOutboxTransaction(behavior, connectionManager, System.Data.IsolationLevel.ReadCommitted));
        },
            cleanupBatchSize: 5);

        using (var connection = GetConnection()(theSchema))
        {
            connection.Open();
            connection.ExecuteCommand(OutboxScriptBuilder.BuildDropScript(sqlDialect), GetTablePrefix(), schema: theSchema);
            connection.ExecuteCommand(OutboxScriptBuilder.BuildCreateScript(sqlDialect), GetTablePrefix(), schema: theSchema);
        }
        return(persister);
    }
    public void Store()
    {
        var timeoutCommands = OutboxCommandBuilder.Build("TheTablePrefix", sqlDialect);

        Approver.Verify(timeoutCommands.Store, scenario: GetType().Name);
    }
Пример #9
0
    public void Write()
    {
        var directory = Path.Combine(TestContext.CurrentContext.TestDirectory, "../../../");

        foreach (var variant in Enum.GetValues(typeof(BuildSqlDialect)).Cast <BuildSqlDialect>())
        {
            Write(directory, variant, "TimeoutCreate", TimeoutScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "TimeoutDrop", TimeoutScriptBuilder.BuildDropScript(variant));

            Write(directory, variant, "OutboxCreate", OutboxScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "OutboxDrop", OutboxScriptBuilder.BuildDropScript(variant));

            Write(directory, variant, "SubscriptionCreate", SubscriptionScriptBuilder.BuildCreateScript(variant));
            Write(directory, variant, "SubscriptionDrop", SubscriptionScriptBuilder.BuildDropScript(variant));

            var sagaDefinition = new SagaDefinition(
                tableSuffix: "OrderSaga",
                name: "OrderSaga",
                correlationProperty: new CorrelationProperty(
                    name: "OrderNumber",
                    type: CorrelationPropertyType.Int),
                transitionalCorrelationProperty: new CorrelationProperty(
                    name: "OrderId",
                    type: CorrelationPropertyType.Guid));
            Write(directory, variant, "SagaCreate", SagaScriptBuilder.BuildCreateScript(sagaDefinition, variant));
            Write(directory, variant, "SagaDrop", SagaScriptBuilder.BuildDropScript(sagaDefinition, variant));
        }

        var dialects = new SqlDialect[]
        {
            new SqlDialect.MsSqlServer(),
            new SqlDialect.MySql(),
            new SqlDialect.Oracle(),
            new SqlDialect.PostgreSql()
        };

        foreach (var dialect in dialects)
        {
            var timeoutCommands = TimeoutCommandBuilder.Build(
                sqlDialect: dialect,
                tablePrefix: "EndpointName");
            Write(directory, dialect, "TimeoutAdd", timeoutCommands.Add);
            Write(directory, dialect, "TimeoutNext", timeoutCommands.Next);
            Write(directory, dialect, "TimeoutRange", timeoutCommands.Range);
            Write(directory, dialect, "TimeoutRemoveById", timeoutCommands.RemoveById);
            Write(directory, dialect, "TimeoutRemoveBySagaId", timeoutCommands.RemoveBySagaId);
            Write(directory, dialect, "TimeoutPeek", timeoutCommands.Peek);

            var outboxCommands = OutboxCommandBuilder.Build(
                tablePrefix: "EndpointName",
                sqlDialect: dialect);
            Write(directory, dialect, "OutboxCleanup", outboxCommands.Cleanup);
            Write(directory, dialect, "OutboxGet", outboxCommands.Get);
            Write(directory, dialect, "OutboxSetAsDispatched", outboxCommands.SetAsDispatched);
            Write(directory, dialect, "OutboxStore", outboxCommands.Store);

            var subscriptionCommands = SubscriptionCommandBuilder.Build(
                sqlDialect: dialect,
                tablePrefix: "EndpointName");
            Write(directory, dialect, "SubscriptionSubscribe", subscriptionCommands.Subscribe);
            Write(directory, dialect, "SubscriptionUnsubscribe", subscriptionCommands.Unsubscribe);
            Write(directory, dialect, "SubscriptionGetSubscribers", subscriptionCommands.GetSubscribers(new List <MessageType>
            {
                new MessageType("MessageTypeName", new Version())
            }));

            Write(directory, dialect, "SagaComplete", dialect.BuildCompleteCommand("EndpointName_SagaName"));
            Write(directory, dialect, "SagaGetByProperty", dialect.BuildGetByPropertyCommand("PropertyName", "EndpointName_SagaName"));
            Write(directory, dialect, "SagaGetBySagaId", dialect.BuildGetBySagaIdCommand("EndpointName_SagaName"));
            Write(directory, dialect, "SagaSave", dialect.BuildSaveCommand("CorrelationProperty", "TransitionalCorrelationProperty", "EndpointName_SagaName"));
            Write(directory, dialect, "SagaUpdate", dialect.BuildUpdateCommand("TransitionalCorrelationProperty", "EndpointName_SagaName"));

            // since we don't have doco on oracle saga finders
            if (!(dialect is SqlDialect.Oracle))
            {
                var createSelectWithWhereClause = dialect.BuildSelectFromCommand("EndpointName_SagaName");
                Write(directory, dialect, "SagaSelect", createSelectWithWhereClause("1 = 1"));
            }
        }
    }
Пример #10
0
    protected override void Setup(FeatureConfigurationContext context)
    {
        var settings          = context.Settings;
        var connectionManager = settings.GetConnectionBuilder <StorageType.Outbox>();
        var tablePrefix       = settings.GetTablePrefix();
        var sqlDialect        = settings.GetSqlDialect();

        var pessimisticMode      = context.Settings.GetOrDefault <bool>(ConcurrencyMode);
        var transactionScopeMode = context.Settings.GetOrDefault <bool>(TransactionMode);

        var outboxCommands = OutboxCommandBuilder.Build(sqlDialect, tablePrefix);

        ConcurrencyControlStrategy concurrencyControlStrategy;

        if (pessimisticMode)
        {
            concurrencyControlStrategy = new PessimisticConcurrencyControlStrategy(sqlDialect, outboxCommands);
        }
        else
        {
            concurrencyControlStrategy = new OptimisticConcurrencyControlStrategy(sqlDialect, outboxCommands);
        }

        ISqlOutboxTransaction transactionFactory()
        {
            return(transactionScopeMode
                ? (ISqlOutboxTransaction) new TransactionScopeSqlOutboxTransaction(concurrencyControlStrategy, connectionManager)
                : new AdoNetSqlOutboxTransaction(concurrencyControlStrategy, connectionManager));
        }

        var outboxPersister = new OutboxPersister(connectionManager, sqlDialect, outboxCommands, transactionFactory);

        context.Container.ConfigureComponent(b => outboxPersister, DependencyLifecycle.InstancePerCall);

        if (settings.GetOrDefault <bool>(DisableCleanup))
        {
            settings.AddStartupDiagnosticsSection("NServiceBus.Persistence.Sql.Outbox", new
            {
                CleanupDisabled = true
            });

            return;
        }

        if (settings.EndpointIsMultiTenant())
        {
            throw new Exception($"{nameof(SqlPersistenceConfig.MultiTenantConnectionBuilder)} can only be used with the Outbox feature if Outbox cleanup is handled by an external process (i.e. SQL Agent) and the endpoint is configured to disable Outbox cleanup using endpointConfiguration.EnableOutbox().{nameof(SqlPersistenceOutboxSettingsExtensions.DisableCleanup)}(). See the SQL Persistence documentation for more information on how to clean up Outbox tables from a scheduled task.");
        }

        var frequencyToRunCleanup       = settings.GetOrDefault <TimeSpan?>(FrequencyToRunDeduplicationDataCleanup) ?? TimeSpan.FromMinutes(1);
        var timeToKeepDeduplicationData = settings.GetOrDefault <TimeSpan?>(TimeToKeepDeduplicationData) ?? TimeSpan.FromDays(7);

        settings.AddStartupDiagnosticsSection("NServiceBus.Persistence.Sql.Outbox", new
        {
            CleanupDisabled                        = false,
            TimeToKeepDeduplicationData            = timeToKeepDeduplicationData,
            FrequencyToRunDeduplicationDataCleanup = frequencyToRunCleanup
        });

        context.RegisterStartupTask(b =>
                                    new OutboxCleaner(outboxPersister.RemoveEntriesOlderThan, b.Build <CriticalError>().Raise, timeToKeepDeduplicationData, frequencyToRunCleanup, new AsyncTimer()));
    }
    public void SetAsDispatched()
    {
        var timeoutCommands = OutboxCommandBuilder.Build(sqlDialect, "TheTablePrefix");

        Approver.Verify(timeoutCommands.SetAsDispatched, scenario: GetType().Name);
    }
    public void Cleanup()
    {
        var timeoutCommands = OutboxCommandBuilder.Build(sqlDialect, "TheTablePrefix");

        Approver.Verify(timeoutCommands.Cleanup, scenario: GetType().Name);
    }
    public void Complete()
    {
        var outboxCommands = OutboxCommandBuilder.Build(sqlDialect, "TheTablePrefix");

        Approver.Verify(outboxCommands.PessimisticComplete, scenario: GetType().Name);
    }
    public void Store()
    {
        var outboxCommands = OutboxCommandBuilder.Build(sqlDialect, "TheTablePrefix");

        Approver.Verify(outboxCommands.OptimisticStore, scenario: GetType().Name);
    }