rebus-org / Rebus.PostgreSql

:bus: PostgreSQL persistence for Rebus
https://mookid.dk/category/rebus
Other
18 stars 20 forks source link

Rebus eagerly commiting and disposing connections when I don't want it to #10

Closed kasparkallas closed 5 years ago

kasparkallas commented 5 years ago

Hello!

In my application, I want to put all database operations happening during a single HTTP request inside a corresponding transaction, so that everything fails or everything succeeds. Publishing through Rebus is a part of it. My application would have full control of the transactions.

A slight problem with Rebus arouse that Rebus would be eagerly commiting and disposing Npgsql transactions (reference: PostgresqlTransport.cs).

I solved it by configuring Rebus with a custom IPostgresConnectionProvider that provides a "connection" which can not be completed/finished:

public class NotFinishingPostgresConnection : PostgresConnection, IDisposable
{
    private readonly NpgsqlConnection _currentConnection;
    private readonly NpgsqlTransaction _currentTransaction;

    public NotFinishingPostgresConnection(NpgsqlConnection currentConnection, NpgsqlTransaction currentTransaction) : base(currentConnection, currentTransaction)
    {
        _currentConnection = currentConnection;
        _currentTransaction = currentTransaction;
    }

    public new Task Complete()
    {
        return Task.CompletedTask;
    }

    public new void Dispose()
    {
    }
}

The problem with this is that it uses quite ugly new keywords to achieve the functionality...

And even with this "not finishing connection", Rebus still somehow completed the transactions when there were multiple sendings/publishings through rebus during a request. I solved that by wrapping the HTTP request (using a ASP.NET MVC Middleware) in RebusTransactionScope that does nothing other than group the Rebus operations so that I could commit them later myself.

So I have the solutions and it's working correctly now. But I just wanted to do a little write-up if someone else has the same problem or something could be changed in the Rebus.PostgreSql code-base (e.g. make PostgresConnection's Complete() & Dispose() virtual).

mookid8000 commented 5 years ago

Thanks for describing this issue 🙂 have you tried using the default Postgres provider together with RebusTransactionScope?

I would expect a single database transaction then, which would then be committed when the scope is completed.

kasparkallas commented 5 years ago

Thanks for answering

When I make my custom PostgresConnection return:
new PostgresConnection(npsqlTransactionAccessor.CurrentConnection, npsqlTransactionAccessor.CurrentTransaction);
then I get an ObjectDisposedException when I try to commit the transaction later. Even though it's wrapped in RebusTransactionScope which has not been completed yet.

The default provider creates a new connection & transaction which is not what I want.

mookid8000 commented 5 years ago

Hi @kasparkallas , I just made this test, and as far as I can tell, only one single connection is created, even though 5 messages are sent.

Could you maybe try and disable your custom connection provider, and then just use RebusTransactionScope to bundle your outgoing messages?

Please let me know if it doesn't work out as expected. I'm closing this one for now 🙂