Particular / NServiceBus.TransactionalSession

Transactional message session implementation for NServiceBus
Other
3 stars 1 forks source link

TransactionalSession with pessimistic concurrency control outbox leads to uncollected messages #376

Open PhilAch opened 4 days ago

PhilAch commented 4 days ago

Describe the bug

Description

The Transactional Session feature can lead to a lot of uncollected messages in the outbox. This happens, when pessimistic concurrency control is used, and no message/command/event is sent or published during the transaction. In this case, an entry is still added to the outbox during opening of the transaction. But it is never cleaned up later on, as only entries marked as dispatched are deleted.

Expected behavior

Honestly not sure, what should be expected. Maybe it is not supposed to be used in such a configuration, an we have since moved away from pessimistic concurrency for the transactional session endpoint, as there is no real value in it. Maybe it should just be mentioned in the documentation, or better, show some warning or error during startup, if it is not supported.

Actual behavior

Messages are added to the outbox, but never cleaned up afterwards.

Versions

NServiceBus.TransactionalSession 3.2.0 NServiceBus.Persistence.Sql 8.1.0 NServiceBus.Persistence.Sql.TransactionalSession 8.1.0 NServiceBus.Extensions.Hosting 3.0.0

Steps to reproduce

Small sample application to reproduce the issue.

var connectionString = builder.Configuration.GetConnectionString("mssql");

var endpointConfiguration = new EndpointConfiguration("Samples.ASPNETCore.Sender");

endpointConfiguration.UseSerialization<SystemJsonSerializer>();
endpointConfiguration.EnableInstallers();
endpointConfiguration.UseTransport(new LearningTransport { TransportTransactionMode = TransportTransactionMode.ReceiveOnly });

var persistence = endpointConfiguration.UsePersistence<SqlPersistence>();
persistence.SqlDialect<SqlDialect.MsSqlServer>();
persistence.ConnectionBuilder(() => new SqlConnection(connectionString));

persistence.EnableTransactionalSession();

var outbox = endpointConfiguration.EnableOutbox();
outbox.RunDeduplicationDataCleanupEvery(TimeSpan.FromSeconds(1));
outbox.KeepDeduplicationDataFor(TimeSpan.FromSeconds(30));
outbox.UsePessimisticConcurrencyControl();

builder.UseNServiceBus(endpointConfiguration);
[HttpPost("TransactionSession")]
public async Task<IActionResult> TransactionSession([FromServices] ITransactionalSession session)
{
    await session.Open(new SqlPersistenceOpenSessionOptions());

    await session.Commit();

    return Ok();
}

Relevant log output

No response

Additional Information

No response

andreasohlund commented 2 days ago

Thanks for reporting this @PhilAch this looks like a bug on our end, we are trying to reproduce it on our end and let you know here about our progress