Skip to content

Implement Polecat primary-store database-per-tenant (GH-3445)#3452

Merged
jeremydmiller merged 1 commit into
mainfrom
fix-3445-polecat-primary-tenancy
Jul 17, 2026
Merged

Implement Polecat primary-store database-per-tenant (GH-3445)#3452
jeremydmiller merged 1 commit into
mainfrom
fix-3445-polecat-primary-tenancy

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3445.

The gap

PolecatIntegration.MainDatabaseConnectionString was documented on the Polecat multi-tenancy page as the way to point Wolverine's envelope storage at a master database under database-per-tenant — but nothing read it. The primary IntegrateWithWolverine() path (WolverineOptionsPolecatExtensions.cs) unconditionally built a single non-tenanted SqlServerMessageStore from store.Options.ConnectionString, with no cardinality branch and no MultiTenantedMessageStore. Because it's a silent no-op rather than a compile error, a user following the docs shipped a system whose tenant messages went to the wrong store.

The PolecatMessageDatabaseSource / MultiTenantedMessageStore machinery already existed — but only on the ancillary path. Marten's primary path has always had the branch (WolverineOptionsMartenExtensions.cs:126-140).

The fix

Mirror the ancillary Polecat path and the Marten twin on the primary path:

  • Dispatch on store.Options.Tenancy.Cardinality (not the tenancy type name — see the ancillary seam's marten#4864 note).
  • For a multi-tenanted store, build a MultiTenantedMessageStore over a PolecatMessageDatabaseSource with a Role.Main master store for tenant-neutral state (nodes, assignments, dead letters), reading MainDatabaseConnectionString (falling back to the store's base connection string, throwing a clear error if neither is present).
  • Single-tenant path is unchanged.

Tests

primary_store_database_per_tenant (SQL Server) asserts the primary store is now a MultiTenantedMessageStore and that durability agents exist for each tenant database. Verified red against origin/main, green with the fix.

Docs (items 2 & 3 from the issue)

  • multi-tenancy.md: the sample called Marten's AddSingleTenantDatabase(conn, tenantId); corrected to Polecat's AddTenant(tenantId, conn) (reversed args).
  • distribution.md: corrected the agent-URI example. Verified against the Polecat source: IEventStore.Identity => new(StoreName.ToLowerInvariant(), "SqlServer") and EventStoreIdentity(string Name, string Type), so UriFor emits {Type}/{Name} = sqlserver/main, not polecat/main.

Dependencies

Bumps Weasel 9.16.4 -> 9.17.0 and the Polecat floor to 5.1.0 (both latest on NuGet). Full wolverine.slnx builds clean in Release.

🤖 Generated with Claude Code

The primary Polecat IntegrateWithWolverine() path unconditionally built a
single non-tenanted SqlServerMessageStore and never read
PolecatIntegration.MainDatabaseConnectionString, so under a database-per-tenant
Polecat store the tenant envelopes silently went to the wrong database — a
no-op, not an error. Mirror the ancillary Polecat path (and the Marten twin in
WolverineOptionsMartenExtensions): dispatch on tenancy cardinality and, for a
multi-tenanted store, build a MultiTenantedMessageStore over a
PolecatMessageDatabaseSource with a Role.Main master store for tenant-neutral
state, reading MainDatabaseConnectionString. Cardinality is checked rather than
the tenancy's type name (see the ancillary seam's marten#4864 note).

Test: primary_store_database_per_tenant proves the primary store is now a
MultiTenantedMessageStore and durability agents exist for each tenant database.
Verified red against origin/main, green with the fix.

Docs: fix the multi-tenancy sample to use Polecat's AddTenant(tenantId, conn)
instead of Marten's AddSingleTenantDatabase(conn, tenantId), and correct the
distribution page's agent-URI example — Polecat's IEventStore.Identity.Type is
its storage engine "SqlServer" (lowercased in the URI), not "polecat".

Also bump Weasel 9.16.4 -> 9.17.0 and the Polecat floor to 5.1.0 (latest).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit 53b64d3 into main Jul 17, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Polecat: primary-store database-per-tenant is documented but not implemented

1 participant