You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while fixing #3815. Distinct from that issue and larger: #3815 is an off-by-one fan-out, this is that MySQL has no per-tenant queue tables at all.
The shape
In MySQL a schema is a database. MySqlTransport.TransportSchemaName defaults to "wolverine_queues" and the queue tables are qualified with it unconditionally:
So every tenant data source, whatever database its connection string names, resolves wolverine_queues.wolverine_queue_<name> to the same physical table on that server. The per-tenant fan-out in MultiTenantedQueueSender / MultiTenantedQueueListener / forEveryDatabase picks a different connection per tenant, but they all land on one table.
PostgreSQL is unaffected: its TransportSchemaName is a schema nested inside each tenant database, so each tenant genuinely has its own copy.
Observed
A host with RegisterStaticTenants for three tenant databases plus the main one, publishing to a MySQL queue.
With 10 rows physically present in the single MySQL table, CountAsync() returned 40 — the same table counted once per tenant data source.
Why it matters
No tenant isolation for MySQL queues. Every tenant's sends land in one table, and a listener on any tenant connection can pick up another tenant's messages. Depending on how the listener filters, this is either cross-tenant delivery or a shared work queue masquerading as a partitioned one.
PurgeAsync/SetupAsync/TeardownAsync/CheckAsync all repeat their work N times against one table.
Caveat on scope
This only bites when the tenant databases live on the same MySQL server — which is what RegisterStaticTenants with connection strings differing only by Database= produces, and the common multi-tenancy-by-database setup. Tenants on separate servers each get their own wolverine_queues database and behave correctly.
Not verified
Oracle uses the same fixed-schema pattern (TransportSchemaName = "WOLVERINE_QUEUES", and in Oracle a schema is a user), so it may have the same exposure depending on whether tenants land on separate instances/PDBs or separate users on one instance. There is no Oracle multi-tenancy test fixture to settle it with.
Likely directions
Derive the queue table's schema from the tenant's own database rather than a single transport-wide name, so MySQL gets per-tenant tables the way PostgreSQL does.
Or, if a shared queue table is the intended MySQL model, stop fanning forEveryDatabase out over tenants for MySQL entirely (visit the transport's one database once) and document that MySQL queues are not tenant-isolated.
(1) matches every other transport's semantics; (2) is smaller but changes what multi-tenanted MySQL queues promise.
Found while fixing #3815. Distinct from that issue and larger: #3815 is an off-by-one fan-out, this is that MySQL has no per-tenant queue tables at all.
The shape
In MySQL a schema is a database.
MySqlTransport.TransportSchemaNamedefaults to"wolverine_queues"and the queue tables are qualified with it unconditionally:So every tenant data source, whatever database its connection string names, resolves
wolverine_queues.wolverine_queue_<name>to the same physical table on that server. The per-tenant fan-out inMultiTenantedQueueSender/MultiTenantedQueueListener/forEveryDatabasepicks a different connection per tenant, but they all land on one table.PostgreSQL is unaffected: its
TransportSchemaNameis a schema nested inside each tenant database, so each tenant genuinely has its own copy.Observed
A host with
RegisterStaticTenantsfor three tenant databases plus the main one, publishing to a MySQL queue.MySQL — four databases, one queue table:
PostgreSQL, same configuration — one queue table per database:
With 10 rows physically present in the single MySQL table,
CountAsync()returned 40 — the same table counted once per tenant data source.Why it matters
CountAsync()/ScheduledCountAsync()multiply by the tenant count, soGetAttributesAsync()reports a queue depth that is N times the truth. OracleQueue.CountAsync double-counts on a multi-tenanted store: forEveryDatabase visits Main twice #3815 reduces the multiplier from N+1 to N; it does not fix this.PurgeAsync/SetupAsync/TeardownAsync/CheckAsyncall repeat their work N times against one table.Caveat on scope
This only bites when the tenant databases live on the same MySQL server — which is what
RegisterStaticTenantswith connection strings differing only byDatabase=produces, and the common multi-tenancy-by-database setup. Tenants on separate servers each get their ownwolverine_queuesdatabase and behave correctly.Not verified
Oracle uses the same fixed-schema pattern (
TransportSchemaName = "WOLVERINE_QUEUES", and in Oracle a schema is a user), so it may have the same exposure depending on whether tenants land on separate instances/PDBs or separate users on one instance. There is no Oracle multi-tenancy test fixture to settle it with.Likely directions
forEveryDatabaseout over tenants for MySQL entirely (visit the transport's one database once) and document that MySQL queues are not tenant-isolated.(1) matches every other transport's semantics; (2) is smaller but changes what multi-tenanted MySQL queues promise.