public async Task Should_update_dispatched_flag()
        {
            var persister = new OutboxPersister(store, testEndpointName, CreateTestSessionOpener());

            var id      = Guid.NewGuid().ToString("N");
            var message = new OutboxMessage(id, new []
            {
                new TransportOperation(id, new Dictionary <string, string>(), new byte[1024 * 5], new Dictionary <string, string>())
            });

            using (var transaction = await persister.BeginTransaction(new ContextBag()))
            {
                await persister.Store(message, transaction, new ContextBag());

                await transaction.Commit();
            }
            await persister.SetAsDispatched(id, new ContextBag());

            WaitForIndexing();

            using (var s = store.OpenAsyncSession())
            {
                var result = await s.Query <OutboxRecord>()
                             .SingleOrDefaultAsync(o => o.MessageId == id);

                Assert.NotNull(result);
                Assert.True(result.Dispatched);
            }
        }
Ejemplo n.º 2
0
 public OutboxCleaner(OutboxPersister outboxPersister, TimeSpan timeToKeepDeduplicationData, TimeSpan frequencyToRunCleanup)
 {
     cancellationTokenSource = new CancellationTokenSource();
     this.timeToKeepDeduplicationData = timeToKeepDeduplicationData;
     this.frequencyToRunCleanup = frequencyToRunCleanup;
     this.outboxPersister = outboxPersister;
 }
Ejemplo n.º 3
0
        public void Setup()
        {
            var mapper = new ModelMapper();

            mapper.AddMapping <OutboxEntityMap>();

            var configuration = new global::NHibernate.Cfg.Configuration()
                                .AddProperties(new Dictionary <string, string>
            {
                { "dialect", dialect },
                { global::NHibernate.Cfg.Environment.ConnectionString, connectionString }
            });

            configuration.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());

            new SchemaUpdate(configuration).Execute(false, true);

            SessionFactory = configuration.BuildSessionFactory();

            Session = SessionFactory.OpenSession();

            persister = new OutboxPersister
            {
                StorageSessionProvider = new FakeSessionProvider(SessionFactory, Session),
                EndpointName           = "TestEndpoint"
            };
        }
Ejemplo n.º 4
0
    protected override void Setup(FeatureConfigurationContext context)
    {
        var settings          = context.Settings;
        var connectionBuilder = settings.GetConnectionBuilder <StorageType.Outbox>();
        var tablePrefix       = settings.GetTablePrefix();
        var sqlDialect        = settings.GetSqlDialect();
        var outboxPersister   = new OutboxPersister(connectionBuilder, tablePrefix, sqlDialect);

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

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

            return;
        }

        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()));
    }
Ejemplo n.º 5
0
    static async Task Store(int i, OutboxPersister persister, CancellationToken cancellationToken = default)
    {
        var operations = new[]
        {
            new TransportOperation(
                messageId: "OperationId" + i,
                properties: new DispatchProperties(new Dictionary <string, string>
            {
                {
                    "OptionKey1", "OptionValue1"
                }
            }),
                body: new byte[]
            {
                0x20
            },
                headers: new Dictionary <string, string>
            {
                {
                    "HeaderKey1", "HeaderValue1"
                }
            }
                )
        };
        var messageId  = "MessageId" + i;
        var contextBag = CreateContextBag(messageId);

        using (var transaction = await persister.BeginTransaction(contextBag, cancellationToken))
        {
            await persister.Store(new OutboxMessage(messageId, operations), transaction, contextBag, cancellationToken).ConfigureAwait(false);

            await transaction.Commit(cancellationToken);
        }
        await persister.SetAsDispatched(messageId, contextBag, cancellationToken).ConfigureAwait(false);
    }
        public async Task Should_store_expiry_in_metadata_if_time_to_keep_deduplication_data_is_finite()
        {
            // arrange
            var timeToKeepDeduplicationData = TimeSpan.FromSeconds(60);
            var persister         = new OutboxPersister("TestEndpoint", CreateTestSessionOpener(), timeToKeepDeduplicationData);
            var context           = new ContextBag();
            var incomingMessageId = SimulateIncomingMessage(context).MessageId;
            var outboxRecordId    = "Outbox/TestEndpoint/" + incomingMessageId;

            //manually store an OutboxRecord to control the OutboxRecordId format
            using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency())
            {
                await session.StoreAsync(new OutboxRecord { MessageId = incomingMessageId, Dispatched = false, }, outboxRecordId);

                await session.SaveChangesAsync();
            }

            var expectedExpiry           = DateTime.UtcNow.Add(timeToKeepDeduplicationData);
            var maxExpectedExecutionTime = TimeSpan.FromMinutes(15);

            // act
            await persister.SetAsDispatched(incomingMessageId, context);

            // assert
            using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency())
            {
                var outboxRecord = await session.LoadAsync <OutboxRecord>(outboxRecordId);

                var metadata = session.Advanced.GetMetadataFor(outboxRecord);
                var expiry   = DateTime.Parse((string)metadata[Constants.Documents.Metadata.Expires], default, DateTimeStyles.RoundtripKind);
Ejemplo n.º 7
0
    async Task Store(int i, DbConnection connection, OutboxPersister persister)
    {
        var operations = new[]
        {
            new TransportOperation(
                messageId: "OperationId" + i,
                options: new Dictionary <string, string>
            {
                {
                    "OptionKey1", "OptionValue1"
                }
            },
                body: new byte[]
            {
                0x20
            },
                headers: new Dictionary <string, string>
            {
                {
                    "HeaderKey1", "HeaderValue1"
                }
            }
                )
        };
        var messageId     = "MessageId" + i;
        var outboxMessage = new OutboxMessage(messageId, operations);

        using (var transaction = connection.BeginTransaction())
        {
            await persister.Store(outboxMessage, transaction, connection).ConfigureAwait(false);

            transaction.Commit();
        }
        await persister.SetAsDispatched(messageId, null).ConfigureAwait(false);
    }
Ejemplo n.º 8
0
    async Task <OutboxMessage> StoreAndGetAsync(OutboxPersister persister)
    {
        var operations = new[]
        {
            new TransportOperation(
                messageId: "Id1",
                options: new Dictionary <string, string>
            {
                {
                    "OptionKey1", "OptionValue1"
                }
            },
                body: new byte[] { 0x20, 0x21 },
                headers: new Dictionary <string, string>
            {
                {
                    "HeaderKey1", "HeaderValue1"
                }
            }
                )
        };

        var messageId = "a";

        using (var connection = await connectionManager.OpenNonContextualConnection().ConfigureAwait(false))
            using (var transaction = connection.BeginTransaction())
            {
                await persister.Store(new OutboxMessage(messageId, operations), transaction, connection).ConfigureAwait(false);

                transaction.Commit();
            }
        return(await persister.Get(messageId, null).ConfigureAwait(false));
    }
        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);
        }
        public void Should_update_dispatched_flag()
        {
            var id = Guid.NewGuid().ToString("N");

            var sessionFactory = new RavenSessionFactory(store);
            var persister = new OutboxPersister(sessionFactory) { DocumentStore = store, EndpointName = "TestEndpoint" };
            persister.Store(id, new List<TransportOperation>
            {
                new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>()),
            });

            sessionFactory.SaveChanges();
            sessionFactory.ReleaseSession();

            persister.SetAsDispatched(id);

            WaitForIndexing(store);

            using (var session = store.OpenSession())
            {
                var result = session.Query<OutboxRecord>().Where(o => o.MessageId == id)
                    .SingleOrDefault();

                Assert.NotNull(result);
                Assert.True(result.Dispatched);
            }
        }
        public async Task Should_get_messages()
        {
            var persister = new OutboxPersister(store, testEndpointName, CreateTestSessionOpener());

            var messageId = Guid.NewGuid().ToString();

            //manually store an OutboxRecord to control the OutboxRecordId format
            using (var session = OpenAsyncSession())
            {
                var newRecord = new OutboxRecord
                {
                    MessageId           = messageId,
                    Dispatched          = false,
                    TransportOperations = new[]
                    {
                        new OutboxRecord.OutboxOperation
                        {
                            Message   = new byte[1024 * 5],
                            Headers   = new Dictionary <string, string>(),
                            MessageId = messageId,
                            Options   = new Dictionary <string, string>()
                        }
                    }
                };
                var fullDocumentId = "Outbox/TestEndpoint/" + messageId;
                await session.StoreAsync(newRecord, fullDocumentId);

                await session.SaveChangesAsync();
            }

            var result = await persister.Get(messageId, new ContextBag());

            Assert.NotNull(result);
            Assert.AreEqual(messageId, result.MessageId);
        }
        public void Should_delete_all_OutboxRecords_that_have_been_dispatched()
        {
            var id = Guid.NewGuid().ToString("N");

            var sessionFactory = new RavenSessionFactory(store);

            var persister = new OutboxPersister(sessionFactory) { DocumentStore = store, EndpointName = "TestEndpoint" };
            persister.Store("NotDispatched", Enumerable.Empty<TransportOperation>());
            persister.Store(id, new List<TransportOperation>
            {
                new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>()),
            });

            sessionFactory.SaveChanges();
            sessionFactory.ReleaseSession();

            persister.SetAsDispatched(id);
            Thread.Sleep(TimeSpan.FromSeconds(1)); //Need to wait for dispatch logic to finish

            WaitForIndexing(store);

            var cleaner = new OutboxRecordsCleaner { DocumentStore = store };
            cleaner.RemoveEntriesOlderThan(DateTime.UtcNow.AddMinutes(1));

            using (var session = store.OpenSession())
            {
                var result = session.Query<OutboxRecord>().ToList();

                Assert.AreEqual(1, result.Count);
                Assert.AreEqual("NotDispatched", result[0].MessageId);
            }
        }
 public OutboxPersisterTests(BuildSqlVarient sqlVarient)
 {
     this.sqlVarient = sqlVarient;
     dbConnection = GetConnection();
     persister = new OutboxPersister(sqlVarient.Convert(),
         connectionBuilder: dbConnection,
         tablePrefix: $"{nameof(OutboxPersisterTests)}_");
 }
        public void Connect()
        {
            connection = EventStoreConnection.Create(new IPEndPoint(IPAddress.Loopback, 1113));
            connection.ConnectAsync().GetAwaiter().GetResult();

            persister       = new SagaPersister();
            outboxPersister = new OutboxPersister(null);
        }
 protected override void Setup(FeatureConfigurationContext context)
 {
     context.Settings.EnableFeature<StorageType.Outbox>();
     var settings = context.Settings;
     var connectionBuilder = settings.GetConnectionBuilder<StorageType.Outbox>();
     var sqlVarient = settings.GetSqlVarient();
     var endpointName = settings.GetTablePrefix<StorageType.Outbox>();
     var outboxPersister = new OutboxPersister(sqlVarient, connectionBuilder, endpointName);
     context.Container.ConfigureComponent(b => outboxPersister, DependencyLifecycle.InstancePerCall);
 }
    protected override void Setup(FeatureConfigurationContext context)
    {
        var settings          = context.Settings;
        var connectionBuilder = settings.GetConnectionBuilder();
        var tablePrefix       = settings.GetTablePrefix();
        var sqlDialect        = settings.GetSqlDialect();
        var outboxPersister   = new OutboxPersister(connectionBuilder, tablePrefix, sqlDialect);

        context.Container.ConfigureComponent(b => outboxPersister, DependencyLifecycle.InstancePerCall);
        context.RegisterStartupTask(b => new OutboxCleaner(outboxPersister.RemoveEntriesOlderThan, b.Build <CriticalError>().Raise, TimeSpan.FromDays(7), TimeSpan.FromMinutes(1), new AsyncTimer()));
    }
        public void Should_throw_if__trying_to_insert_same_messageid2()
        {
            var sessionFactory = new RavenSessionFactory(store);
            var persister = new OutboxPersister(sessionFactory) { EndpointName = "TestEndpoint" };

            persister.Store("MySpecialId", Enumerable.Empty<TransportOperation>());
            sessionFactory.SaveChanges();
            sessionFactory.ReleaseSession();

            persister.Store("MySpecialId", Enumerable.Empty<TransportOperation>());
            Assert.Throws<ConcurrencyException>(sessionFactory.SaveChanges);
        }
Ejemplo n.º 18
0
        public OutboxPersisterTests()
        {
            _dbContext = new TestDbContext();

            _mockFactory = new Mock <INServiceBusDbContextFactory>();
            _mockFactory.Setup(m => m.CreateTimeoutDbContext()).Returns(new TestDbContext());

            _persister = new OutboxPersister(_mockFactory.Object);

            _dbContext.OutboxRecords.RemoveRange(_dbContext.OutboxRecords);
            _dbContext.SaveChanges();
        }
        public void Should_throw_if__trying_to_insert_same_messageid()
        {
            var sessionFactory = new RavenSessionFactory(store);
            var persister = new OutboxPersister(sessionFactory) { EndpointName = "TestEndpoint" };
            persister.EndpointName = "TestEndpoint";

            using (sessionFactory.Session)
            {
                persister.Store("MySpecialId", Enumerable.Empty<TransportOperation>());
                Assert.Throws<NonUniqueObjectException>(() => persister.Store("MySpecialId", Enumerable.Empty<TransportOperation>()));

                sessionFactory.SaveChanges();
            }
        }
Ejemplo n.º 20
0
 public void Setup()
 {
     persister = new OutboxPersister(
         connectionBuilder: dbConnection,
         tablePrefix: $"{GetTablePrefix()}_",
         schema: schema,
         sqlVariant: sqlVariant.Convert(),
         cleanupBatchSize: 5);
     using (var connection = dbConnection())
     {
         connection.Open();
         connection.ExecuteCommand(OutboxScriptBuilder.BuildDropScript(sqlVariant), GetTablePrefix(), schema: schema);
         connection.ExecuteCommand(OutboxScriptBuilder.BuildCreateScript(sqlVariant), GetTablePrefix(), schema: schema);
     }
 }
Ejemplo n.º 21
0
    OutboxPersister Setup(string theSchema)
    {
        var persister = new OutboxPersister(
            connectionManager: connectionManager,
            tablePrefix: $"{GetTablePrefix()}_",
            sqlDialect: sqlDialect.Convert(theSchema),
            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 async Task Should_throw_if__trying_to_insert_same_messageid_concurrently()
        {
            var persister = new OutboxPersister(store, testEndpointName, CreateTestSessionOpener());

            var exception = await Catch <NonUniqueObjectException>(async() =>
            {
                using (var transaction = await persister.BeginTransaction(new ContextBag()))
                {
                    await persister.Store(new OutboxMessage("MySpecialId", new TransportOperation[0]), transaction, new ContextBag());
                    await persister.Store(new OutboxMessage("MySpecialId", new TransportOperation[0]), transaction, new ContextBag());
                    await transaction.Commit();
                }
            });

            Assert.NotNull(exception);
        }
        public async Task Should_throw_if__trying_to_insert_same_messageid_concurrently()
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var exception = await Catch<NonUniqueObjectException>(async () =>
            {
                using (var transaction = await persister.BeginTransaction(new ContextBag()))
                {
                    await persister.Store(new OutboxMessage("MySpecialId", new TransportOperation[0]), transaction, new ContextBag());
                    await persister.Store(new OutboxMessage("MySpecialId", new TransportOperation[0]), transaction, new ContextBag());
                    await transaction.Commit();
                }
            });

            Assert.NotNull(exception);
        }
        public async Task Should_delete_all_OutboxRecords_that_have_been_dispatched()
        {
            var id      = Guid.NewGuid().ToString("N");
            var context = new ContextBag();

            var persister = new OutboxPersister(store, "TestEndpoint", CreateTestSessionOpener());

            using (var transaction = await persister.BeginTransaction(context))
            {
                await persister.Store(new OutboxMessage("NotDispatched", new TransportOperation[0]), transaction, context);

                await transaction.Commit();
            }

            var outboxMessage = new OutboxMessage(id, new []
            {
                new TransportOperation(id, new Dictionary <string, string>(), new byte[1024 * 5], new Dictionary <string, string>())
            });


            using (var transaction = await persister.BeginTransaction(context))
            {
                await persister.Store(outboxMessage, transaction, context);

                await transaction.Commit();
            }


            await persister.SetAsDispatched(id, context);

            await Task.Delay(TimeSpan.FromSeconds(1)); //Need to wait for dispatch logic to finish

            //WaitForUserToContinueTheTest(store);
            WaitForIndexing();

            var cleaner = new OutboxRecordsCleaner(store);

            await cleaner.RemoveEntriesOlderThan(DateTime.UtcNow.AddMinutes(1));

            using (var s = store.OpenAsyncSession())
            {
                var result = await s.Query <OutboxRecord>().ToListAsync();

                Assert.AreEqual(1, result.Count);
                Assert.AreEqual("NotDispatched", result[0].MessageId);
            }
        }
Ejemplo n.º 25
0
        public async Task Configure()
        {
            var databaseSettings = new MongoDatabaseSettings
            {
                ReadConcern    = ReadConcern.Majority,
                ReadPreference = ReadPreference.Primary,
                WriteConcern   = WriteConcern.WMajority
            };

            var database = ClientProvider.Client.GetDatabase(DatabaseName, databaseSettings);

            await database.CreateCollectionAsync(CollectionNamingConvention(typeof(OutboxRecord)));

            MongoDB.OutboxStorage.InitializeOutboxTypes(ClientProvider.Client, DatabaseName, CollectionNamingConvention, TimeSpan.FromHours(1));

            OutboxStorage = new OutboxPersister(ClientProvider.Client, DatabaseName, CollectionNamingConvention);
        }
        public async Task Should_delete_all_OutboxRecords_that_have_been_dispatched()
        {
            var id = Guid.NewGuid().ToString("N");
            var context = new ContextBag();

            var persister = new OutboxPersister(store, "TestEndpoint");

            using (var transaction = await persister.BeginTransaction(context))
            {
                await persister.Store(new OutboxMessage("NotDispatched", new TransportOperation[0]), transaction, context);

                await transaction.Commit();
            }

            var outboxMessage = new OutboxMessage(id, new []
                {
                    new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>())
                });


            using (var transaction = await persister.BeginTransaction(context))
            {
                await persister.Store(outboxMessage, transaction, context);
                await transaction.Commit();
            }


            await persister.SetAsDispatched(id, context);
            await Task.Delay(TimeSpan.FromSeconds(1)); //Need to wait for dispatch logic to finish

            //WaitForUserToContinueTheTest(store);
            WaitForIndexing(store);

            var cleaner = new OutboxRecordsCleaner(store);

            await cleaner.RemoveEntriesOlderThan(DateTime.UtcNow.AddMinutes(1));

            using (var s = store.OpenAsyncSession())
            {
                var result = await s.Query<OutboxRecord>().ToListAsync();

                Assert.AreEqual(1, result.Count);
                Assert.AreEqual("NotDispatched", result[0].MessageId);
            }
        }
    public async Task It_retries_announcing_advance_when_initializing()
    {
        using (var conn = CreateConnection())
        {
            await conn.OpenAsync().ConfigureAwait(false);

            var dispatchedMessages = new List <OutgoingMessage>();
            Task Dispatch(OutgoingMessage operation)
            {
                dispatchedMessages.Add(operation);
                return(Task.CompletedTask);
            }

            await persister.Initialize(Dispatch, conn);

            var announceFailed = false;
            try
            {
                await persister.TryAdvance(op =>
                {
                    if (op.Headers.ContainsKey(RouterDeduplicationHeaders.Advance))
                    {
                        throw new Exception("Simulated");
                    }
                    return(Dispatch(op));
                }, conn);
            }
            catch (Exception)
            {
                announceFailed = true;
            }

            Assert.IsTrue(announceFailed);

            var newPersister = new OutboxPersister(3, "S", "D");
            await newPersister.Initialize(Dispatch, conn);

            var advanceMessage = dispatchedMessages.Single(m => m.Headers.ContainsKey(RouterDeduplicationHeaders.Advance));

            Assert.AreEqual("2", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceEpoch]);
            Assert.AreEqual("6", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadLo]);
            Assert.AreEqual("9", advanceMessage.Headers[RouterDeduplicationHeaders.AdvanceHeadHi]);
        }
    }
    public async Task PrepareTables()
    {
        LogManager.Use <DefaultFactory>().Level(LogLevel.Debug);

        installer = new OutboxInstaller("S");
        persister = new OutboxPersister(3, "S", "D");
        using (var conn = CreateConnection())
        {
            await conn.OpenAsync().ConfigureAwait(false);

            using (var trans = conn.BeginTransaction())
            {
                await installer.Uninstall("D", conn, trans).ConfigureAwait(false);

                await installer.Install("D", conn, trans).ConfigureAwait(false);

                trans.Commit();
            }
        }
    }
        public async Task Should_be_deleted()
        {
            await store.Maintenance.SendAsync(
                new ConfigureExpirationOperation(
                    new ExpirationConfiguration {
                Disabled = false, DeleteFrequencyInSec = 1,
            }));

            // arrange
            var persister                  = new OutboxPersister("TestEndpoint", CreateTestSessionOpener(), TimeSpan.FromSeconds(1));
            var context                    = new ContextBag();
            var incomingMessageId          = SimulateIncomingMessage(context).MessageId;
            var dispatchedOutboxMessage    = new OutboxMessage(incomingMessageId, new TransportOperation[0]);
            var notDispatchedOutboxMessage = new OutboxMessage("NotDispatched", new TransportOperation[0]);

            using (var transaction = await persister.BeginTransaction(context))
            {
                await persister.Store(dispatchedOutboxMessage, transaction, context);

                await persister.Store(notDispatchedOutboxMessage, transaction, context);

                await transaction.Commit();
            }

            await persister.SetAsDispatched(dispatchedOutboxMessage.MessageId, context);

            // act
            // wait for dispatch logic and expiry to finish, not ideal but polling on BASE index is also not great
            await Task.Delay(TimeSpan.FromSeconds(3));

            WaitForIndexing();

            // assert
            using (var session = store.OpenAsyncSession())
            {
                var outboxRecords = await session.Query <OutboxRecord>().ToListAsync();

                Assert.AreEqual(1, outboxRecords.Count);
                Assert.AreEqual(notDispatchedOutboxMessage.MessageId, outboxRecords.Single().MessageId);
            }
        }
Ejemplo n.º 30
0
        public void Setup()
        {
            var mapper = new ModelMapper();

            mapper.AddMapping <OutboxEntityMap>();

            var configuration = new Configuration()
                                .AddProperties(new Dictionary <string, string>
            {
                { "dialect", dialect },
                { Environment.ConnectionString, connectionString }
            });

            configuration.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());

            new SchemaUpdate(configuration).Execute(false, true);

            SessionFactory = configuration.BuildSessionFactory();

            persister = new OutboxPersister(SessionFactory, "TestEndpoint");
        }
        public void Should_save_with_not_dispatched()
        {
            var id = Guid.NewGuid().ToString("N");
            var sessionFactory = new RavenSessionFactory(store);

            var persister = new OutboxPersister(sessionFactory) { DocumentStore = store, EndpointName = "TestEndpoint" };
            persister.Store(id, new List<TransportOperation>
            {
                new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>()),
            });

            sessionFactory.SaveChanges();
            sessionFactory.ReleaseSession();

            OutboxMessage result;
            persister.TryGet(id, out result);

            var operation = result.TransportOperations.Single();

            Assert.AreEqual(id, operation.MessageId);
        }
Ejemplo n.º 32
0
    async Task <Tuple <OutboxMessage, OutboxMessage> > StoreDispatchAndGetAsync(OutboxPersister persister)
    {
        var operations = new List <TransportOperation>
        {
            new TransportOperation(
                messageId: "Id1",
                options: new Dictionary <string, string>
            {
                {
                    "OptionKey1", "OptionValue1"
                }
            },
                body: new byte[] { 0x20, 0x21 },
                headers: new Dictionary <string, string>
            {
                {
                    "HeaderKey1", "HeaderValue1"
                }
            }
                )
        };
        var messageId = "a";

        var contextBag = CreateContextBag(messageId);

        using (var transaction = await persister.BeginTransaction(contextBag))
        {
            await persister.Store(new OutboxMessage(messageId, operations.ToArray()), transaction, contextBag).ConfigureAwait(false);

            await transaction.Commit();
        }

        var beforeDispatch = await persister.Get(messageId, contextBag).ConfigureAwait(false);

        await persister.SetAsDispatched(messageId, contextBag).ConfigureAwait(false);

        var afterDispatch = await persister.Get(messageId, contextBag).ConfigureAwait(false);

        return(Tuple.Create(beforeDispatch, afterDispatch));
    }
        public async Task Should_set_messages_as_dispatched_with_old_and_new_recordId_format(string outboxRecordIdPrefix)
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var messageId = Guid.NewGuid().ToString();

            //manually store an OutboxRecord to control the OutboxRecordId format
            using (var session = OpenSession())
            {
                session.Store(new OutboxRecord
                {
                    Id                  = outboxRecordIdPrefix + messageId,
                    MessageId           = messageId,
                    Dispatched          = false,
                    TransportOperations = new[]
                    {
                        new OutboxRecord.OutboxOperation
                        {
                            Message   = new byte[1024 * 5],
                            Headers   = new Dictionary <string, string>(),
                            MessageId = messageId,
                            Options   = new Dictionary <string, string>()
                        }
                    }
                });

                await session.SaveChangesAsync();
            }

            await persister.SetAsDispatched(messageId, new ContextBag());

            using (var session = OpenSession())
            {
                var result = await session.LoadAsync <OutboxRecord>(outboxRecordIdPrefix + messageId);

                Assert.NotNull(result);
                Assert.True(result.Dispatched);
            }
        }
    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 outboxPersister   = new OutboxPersister(connectionManager, tablePrefix, sqlDialect);

        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 async Task Should_filter_invalid_docid_character()
        {
            var persister = new OutboxPersister(store, testEndpointName, CreateTestSessionOpener());

            var guid                = Guid.NewGuid();
            var messageId           = $@"{guid}\12345";
            var emptyDictionary     = new Dictionary <string, string>();
            var operation           = new TransportOperation("test", emptyDictionary, new byte[0], emptyDictionary);
            var transportOperations = new [] { operation };

            using (var transaction = await persister.BeginTransaction(new ContextBag()))
            {
                await persister.Store(new OutboxMessage(messageId, transportOperations), transaction, new ContextBag());

                await transaction.Commit();
            }

            var outboxMessage = await persister.Get(messageId, new ContextBag());

            Assert.AreEqual(messageId, outboxMessage.MessageId);
            Assert.AreEqual(1, outboxMessage.TransportOperations.Length);
            Assert.AreEqual("test", outboxMessage.TransportOperations[0].MessageId);
        }
        public async Task Should_save_with_not_dispatched()
        {
            var persister = new OutboxPersister(store, testEndpointName, CreateTestSessionOpener());

            var id      = Guid.NewGuid().ToString("N");
            var message = new OutboxMessage(id, new[]
            {
                new TransportOperation(id, new Dictionary <string, string>(), new byte[1024 * 5], new Dictionary <string, string>())
            });

            using (var transaction = await persister.BeginTransaction(new ContextBag()))
            {
                await persister.Store(message, transaction, new ContextBag());

                await transaction.Commit();
            }

            var result = await persister.Get(id, new ContextBag());

            var operation = result.TransportOperations.Single();

            Assert.AreEqual(id, operation.MessageId);
        }
        public async Task Should_save_with_not_dispatched()
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var id = Guid.NewGuid().ToString("N");
            var message = new OutboxMessage(id, new[]
            {
                new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>())
            });

            using (var transaction = await persister.BeginTransaction(new ContextBag()))
            {
                await persister.Store(message, transaction, new ContextBag());

                await transaction.Commit();
            }

            var result = await persister.Get(id, new ContextBag());

            var operation = result.TransportOperations.Single();

            Assert.AreEqual(id, operation.MessageId);
        }
Ejemplo n.º 38
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 async Task Should_set_messages_as_dispatched_with_old_and_new_recordId_format(string outboxRecordIdPrefix)
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var messageId = Guid.NewGuid().ToString();

            //manually store an OutboxRecord to control the OutboxRecordId format
            using (var session = OpenAsyncSession())
            {
                await session.StoreAsync(new OutboxRecord
                {
                    MessageId = messageId,
                    Dispatched = false,
                    TransportOperations = new []
                    {
                        new OutboxRecord.OutboxOperation
                        {
                            Message = new byte[1024*5],
                            Headers = new Dictionary<string, string>(),
                            MessageId = messageId,
                            Options = new Dictionary<string, string>()
                        }
                    }
                }, outboxRecordIdPrefix + messageId);

                await session.SaveChangesAsync();
            }

            await persister.SetAsDispatched(messageId, new ContextBag());

            using (var session = OpenAsyncSession())
            {
                var result = await session.LoadAsync<OutboxRecord>(outboxRecordIdPrefix + messageId);

                Assert.NotNull(result);
                Assert.True(result.Dispatched);
            }
            
        }
        public async Task Should_get_messages_with_old_and_new_recordId_format(string outboxRecordIdPrefix)
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var messageId = Guid.NewGuid().ToString();

            //manually store an OutboxRecord to control the OutboxRecordId format
            using (var session = OpenAsyncSession())
            {
                var newRecord = new OutboxRecord
                {
                    MessageId = messageId,
                    Dispatched = false,
                    TransportOperations = new[]
                    {
                        new OutboxRecord.OutboxOperation
                        {
                            Message = new byte[1024*5],
                            Headers = new Dictionary<string, string>(),
                            MessageId = messageId,
                            Options = new Dictionary<string, string>()
                        }
                    }
                };
                var fullDocumentId = outboxRecordIdPrefix + messageId;
                await session.StoreAsync(newRecord, fullDocumentId);

                await session.SaveChangesAsync();
            }
            
            var result = await persister.Get(messageId, new ContextBag());

            Assert.NotNull(result);
            Assert.AreEqual(messageId, result.MessageId);
        }
        public Task Configure(CancellationToken cancellationToken = default)
        {
            // with this we have a partition key per run which makes things naturally isolated
            partitionKey = Guid.NewGuid().ToString();

            var serializer = new JsonSerializer
            {
                ContractResolver = new UpperCaseIdIntoLowerCaseIdContractResolver(),
                Converters       = { new ReadOnlyMemoryConverter() }
            };

            var persistenceConfiguration = (PersistenceConfiguration)Variant.Values[0];

            var sagaPersistenceConfiguration = new SagaPersistenceConfiguration();

            if (persistenceConfiguration.UsePessimisticLocking)
            {
                var pessimisticLockingConfiguration = sagaPersistenceConfiguration.UsePessimisticLocking();
                if (SessionTimeout.HasValue)
                {
                    pessimisticLockingConfiguration.SetLeaseLockAcquisitionTimeout(SessionTimeout.Value);
                }
                SupportsPessimisticConcurrency = true;
            }

            var partitionKeyPath = new PartitionKeyPath(SetupFixture.PartitionPathKey);
            var resolver         = new ContainerHolderResolver(this, new ContainerInformation(SetupFixture.ContainerName, partitionKeyPath), SetupFixture.DatabaseName);

            SynchronizedStorage = new StorageSessionFactory(resolver, null);
            SagaStorage         = new SagaPersister(serializer, sagaPersistenceConfiguration);
            OutboxStorage       = new OutboxPersister(resolver, serializer, OutboxTimeToLiveInSeconds);

            GetContextBagForSagaStorage = () =>
            {
                var contextBag = new ContextBag();
                // This populates the partition key required to participate in a shared transaction
                var setAsDispatchedHolder = new SetAsDispatchedHolder
                {
                    PartitionKey    = new PartitionKey(partitionKey),
                    ContainerHolder = resolver.ResolveAndSetIfAvailable(contextBag)
                };
                contextBag.Set(setAsDispatchedHolder);
                contextBag.Set(new PartitionKey(partitionKey));
                return(contextBag);
            };

            GetContextBagForOutbox = () =>
            {
                var contextBag = new ContextBag();
                // This populates the partition key required to participate in a shared transaction
                var setAsDispatchedHolder = new SetAsDispatchedHolder
                {
                    PartitionKey    = new PartitionKey(partitionKey),
                    ContainerHolder = resolver.ResolveAndSetIfAvailable(contextBag)
                };
                contextBag.Set(setAsDispatchedHolder);
                contextBag.Set(new PartitionKey(partitionKey));
                return(contextBag);
            };

            return(Task.CompletedTask);
        }
        public async Task Should_update_dispatched_flag()
        {
            var persister = new OutboxPersister(store, testEndpointName);

            var id = Guid.NewGuid().ToString("N");
            var message = new OutboxMessage(id, new []
            {
                new TransportOperation(id, new Dictionary<string, string>(), new byte[1024*5], new Dictionary<string, string>())
            });

            using (var transaction = await persister.BeginTransaction(new ContextBag()))
            {
                await persister.Store(message, transaction, new ContextBag());

                await transaction.Commit();
            }
            await persister.SetAsDispatched(id, new ContextBag());

            WaitForIndexing(store);

            using (var s = store.OpenAsyncSession())
            {
                var result = await s.Query<OutboxRecord>()
                    .SingleOrDefaultAsync(o => o.MessageId == id);

                Assert.NotNull(result);
                Assert.True(result.Dispatched);
            }
        }
        public void Should_set_messages_as_dispatched_with_old_and_new_recordId_format(string outboxRecordIdPrefix)
        {
            var sessionFactory = new RavenSessionFactory(store);
            var persister = new OutboxPersister(sessionFactory) { DocumentStore = store, EndpointName = "TestEndpoint" };

            var messageId = Guid.NewGuid().ToString();

            //manually store an OutboxRecord to control the OutboxRecordId format
            sessionFactory.Session.Store(new OutboxRecord
            {
                MessageId = messageId,
                Dispatched = false,
                TransportOperations = new List<OutboxRecord.OutboxOperation>
                {
                    new OutboxRecord.OutboxOperation
                    {
                        Message = new byte[1024 * 5],
                        Headers = new Dictionary<string, string>(),
                        MessageId = messageId,
                        Options = new Dictionary<string, string>()
                    }
                }
            }, outboxRecordIdPrefix + messageId);

            sessionFactory.SaveChanges();
            sessionFactory.ReleaseSession();

            persister.SetAsDispatched(messageId);
            sessionFactory.ReleaseSession();

            var result = sessionFactory.Session.Load<OutboxRecord>(outboxRecordIdPrefix + messageId);

            Assert.NotNull(result);
            Assert.True(result.Dispatched);
        }
Ejemplo n.º 44
0
 public OutboxCleaner(OutboxPersister outboxPersister, CriticalError criticalError)
 {
     this.outboxPersister = outboxPersister;
     this.criticalError   = criticalError;
 }
Ejemplo n.º 45
0
        public INHibernateOutboxStorage Create(ISessionFactory sessionFactory, string endpointName)
        {
            var persister = new OutboxPersister <T>(sessionFactory, endpointName);

            return(persister);
        }