Stop visiting the main database twice in forEveryDatabase (GH-3815) - #3858
Merged
Conversation
…abase (GH-3815) MultiTenantedMessageStore.ActiveDatabases() yields Main first, and each transport only assigns Databases alongside Store = mt.Main. The Oracle, PostgreSQL and MySQL queues walked both sources, so on any multi-tenanted configuration the main database was visited twice: - CountAsync()/ScheduledCountAsync() double counted every row living in it, and those feed GetAttributesAsync() -- user visible queue depth, measured at "2" for a single row and 5 for 4 rows before this change - CheckAsync() ran its schema diff against it twice - SetupAsync()/PurgeAsync()/TeardownAsync() did their work twice The SqlServer and Sqlite queues already branch if/else here and were never affected; the three are brought in line with them. The existing multi-tenant coverage missed this because it only ever asserts a count of 0, and zero doubled is still zero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JKfy5EzLX1i149gjUb3Tfg
This was referenced Aug 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3815.
The unverified fact resolves to "yes"
#3815 called out one thing that had to be checked before any change: does
MultiTenantedMessageStore.ActiveDatabases()actually includeMain? It does —databases()yields it first:And every affected transport assigns
Databasesonly alongsideStore = mt.Main(checked at both assignment sites —InitializeandConnectAsync— in each). So walkingParent.Storeand then all ofActiveDatabases()hits the main database twice.Measured on a real multi-tenanted Postgres host:
GetAttributesAsync()["Count"]returns"2"for a single row, and 5 for 4 rows.Scope is wider than the title, but not universal
if…ifif…elseThe SqlServer and Sqlite queues already branch the right way, so this PR brings the other three in line with them rather than introducing a new dedupe concept.
What was doubled:
CountAsync()/ScheduledCountAsync()— these feedGetAttributesAsync(), so this is user visible queue depth, not just a test concernCheckAsync()— ran its schema diff against the main database twiceSetupAsync()/PurgeAsync()/TeardownAsync()— did their work twiceWhy no existing test caught it
The multi-tenant coverage in
clear_all_wolverine_storage_across_tenant_databasesassertsCountAsync()is0after a purge — and zero doubled is still zero. The new tests assert a non-zero count, with a row deliberately placed in the main database (an untenanted send lands there).Verification
does_not_double_count_rows_in_the_main_database2vs1still_sums_across_main_and_every_tenant_database5vs4reported_attributes_match_the_physical_row_count"2"vs"1"dotnet build wolverine.slnx -c Release -f net9.0The second test guards the obvious way to get this wrong — trading the double count for a missed tenant database.
A related finding, filed separately
While trying to add the same test for MySQL I found a different and larger problem, tracked in its own issue rather than fixed here: MySQL has no per-tenant queue tables at all. Because a schema is a database in MySQL,
TransportSchemaNameresolves to one fixed database on the server, so the multi-tenant fan-out queries a single physical table once per tenant:…while
CountAsync()reported 40. This PR takes the MySQL multiplier from N+1 down to N, which is strictly closer to correct, but does not resolve that. PostgreSQL is unaffected because its transport schema nests inside each tenant database.🤖 Generated with Claude Code
https://claude.ai/code/session_01JKfy5EzLX1i149gjUb3Tfg