Bug: Multi-tenant Postgres Transport Always Uses Wrong Sender Due to database.Name Being "Default"
Summary
When using Wolverine with a multi-tenant Postgres setup (Postgres as both the application database and the transport), the transport sender resolution fails because all tenant-specific IMessageDatabase objects get the same Name value: "Default".
Since MultiTenantedQueueSender resolves senders using:
_byDatabase.TryFind(database.Name, out sender)
and database.Name is never set uniquely per tenant, every tenant’s database ends up with:
This causes Wolverine to reuse the wrong sender when processing outgoing envelopes for other tenants.
What Actually Happens
-
First tenant request arrives.
Wolverine creates a PostgresqlQueueSender for Tenant 1 and stores it in the dictionary:
"Default" => Sender(Tenant1)
-
Second tenant request arrives.
A new sender for Tenant 2 is created, but the key is again "Default", so the dictionary lookup returns the existing sender for Tenant 1.
-
The Durability Agent attempts to process envelopes using the wrong database connection, leading to errors like:
InvalidOperationException: No matching outgoing envelope
Sending agent for postgresql://shipment_queue/ is latched
As a result, Wolverine runs queue operations against the wrong tenant database.
Root Cause
PostgresqlTenantedMessageStore.buildTenantStoreForConnectionString() does not assign a unique name to each tenant’s IMessageDatabase.
Because of this:
- All tenant DB sources collapse into a single dictionary entry.
- Wolverine always reuses the first sender created.
- Envelope movement fails because the query runs against the wrong database.
Expected Behavior
Each tenant's IMessageDatabase should have a unique, stable name, such as:
- The tenant id, or
- A normalized connection string identifier, or
- A configured logical name.
This ensures MultiTenantedQueueSender correctly resolves the transport sender for the active tenant.
Actual Behavior
All tenants share the name "Default", causing:
- Wrong sender lookup.
- Wrong database connection usage.
- Envelope transitions failing with
InvalidOperationException: No matching outgoing envelope.
How to Reproduce
- Configure Wolverine with:
- Multi-tenant application DB (different schemas or DB servers).
- Multi-tenant Postgres transport.
- Send messages from Tenant 1 and Tenant 2.
- Observe:
-
Outbox inserts occur in the correct tenant DB.
-
The Durability Agent processes envelopes using the wrong tenant connection.
-
Errors like the following appear:
InvalidOperationException: No matching outgoing envelope
Impact
Multi-tenant Postgres transport becomes effectively non-functional, because messages are always routed using the wrong database connection.
Bug: Multi-tenant Postgres Transport Always Uses Wrong Sender Due to
database.NameBeing"Default"Summary
When using Wolverine with a multi-tenant Postgres setup (Postgres as both the application database and the transport), the transport sender resolution fails because all tenant-specific
IMessageDatabaseobjects get the sameNamevalue:"Default".Since
MultiTenantedQueueSenderresolves senders using:and
database.Nameis never set uniquely per tenant, every tenant’s database ends up with:This causes Wolverine to reuse the wrong sender when processing outgoing envelopes for other tenants.
What Actually Happens
First tenant request arrives.
Wolverine creates a
PostgresqlQueueSenderfor Tenant 1 and stores it in the dictionary:Second tenant request arrives.
A new sender for Tenant 2 is created, but the key is again
"Default", so the dictionary lookup returns the existing sender for Tenant 1.The Durability Agent attempts to process envelopes using the wrong database connection, leading to errors like:
As a result, Wolverine runs queue operations against the wrong tenant database.
Root Cause
PostgresqlTenantedMessageStore.buildTenantStoreForConnectionString()does not assign a unique name to each tenant’sIMessageDatabase.Because of this:
Expected Behavior
Each tenant's
IMessageDatabaseshould have a unique, stable name, such as:This ensures
MultiTenantedQueueSendercorrectly resolves the transport sender for the active tenant.Actual Behavior
All tenants share the name
"Default", causing:InvalidOperationException: No matching outgoing envelope.How to Reproduce
Outbox inserts occur in the correct tenant DB.
The Durability Agent processes envelopes using the wrong tenant connection.
Errors like the following appear:
Impact
Multi-tenant Postgres transport becomes effectively non-functional, because messages are always routed using the wrong database connection.