Skip to content

Honor MessageStoreRole for tenanted message stores#3351

Merged
jeremydmiller merged 1 commit into
JasperFx:mainfrom
outofrange-consulting:fix/message-store-role-tenanted
Jul 10, 2026
Merged

Honor MessageStoreRole for tenanted message stores#3351
jeremydmiller merged 1 commit into
JasperFx:mainfrom
outofrange-consulting:fix/message-store-role-tenanted

Conversation

@outofrange-consulting

Copy link
Copy Markdown
Contributor

The bug

PersistMessagesWithPostgresql(cs, "wolverine", role: MessageStoreRole.Ancillary).RegisterStaticTenants(...) produces a store that reports Main, not Ancillary.

BuildMessageStore() applies the configured Role only on the non-tenanted return path:

var settings = buildMainDatabaseSettings();   // Role = MessageStoreRole.Main, hardcoded

if (UseMasterTableTenancy)           return new MultiTenantedMessageStore(...);  // Role never applied
if (ConnectionStringTenancy != null) return new MultiTenantedMessageStore(...);  // Role never applied

settings.Role = Role;                                                            // only here
return new PostgresqlMessageStore(settings, ...);

Why it hurts

In a modular monolith where a module registers an ancillary, statically-tenanted store, the host now has two Main stores. MessageStoreCollection's constructor takes the mains.Length == 1 branch, finds two, and leaves Main as the initial NullMessageStore — no exception, no log line.

From there:

  • WolverineRuntime.tryMigrateStorage() returns early on Storage is NullMessageStore, so the envelope schema is never built;
  • startMessagingTransportsAsync() and the durability agent start anyway.

On PostgreSQL the app then loops forever on 42P01: relation "wolverine.wolverine_nodes" does not exist. The only workaround today is to reach for the store's DemoteToAncillary() after the fact.

The fix

Set Role in buildMainDatabaseSettings() so every return path sees it, and drop the late assignment. Role already defaults to MessageStoreRole.Main, so nothing changes for callers that don't ask for Ancillary.

The same defect is present verbatim in all five relational providers (PostgreSQL, Sql Server, Sqlite, Oracle, MySql); all are fixed here.

Tests

PostgresqlTests/message_store_role_registration.cs — three cases, no database required: ancillary single-database, ancillary with static tenants, and the Main default with static tenants. Mutation-checked: reverting the PostgreSQL fix fails the ancillary-with-tenants test and leaves the other two green.

BuildMessageStore() only applied the configured MessageStoreRole on the
non-tenanted return path, while buildMainDatabaseSettings() hardcoded
Role = Main. A store registered as Ancillary that also registers tenants
therefore came back as Main.

With two Main stores, MessageStoreCollection leaves Main as a
NullMessageStore (no throw, no log), so tryMigrateStorage() skips envelope
schema migration while the durability agent still starts -- on PostgreSQL
the host then loops forever on 42P01: relation "wolverine.wolverine_nodes"
does not exist.

Set the role in buildMainDatabaseSettings() so every return path sees it.
Same defect and fix in the PostgreSQL, Sql Server, Sqlite, Oracle and
MySql providers.
@jeremydmiller
jeremydmiller merged commit 2a5a2ea into JasperFx:main Jul 10, 2026
25 checks passed
jeremydmiller added a commit that referenced this pull request Jul 10, 2026
…iders

Retrofit MessageStoreRole registration tests to all relational providers (#3351 follow-up)
outofrange-consulting pushed a commit to outofrange-consulting/wolverine that referenced this pull request Jul 10, 2026
…Sql, and Oracle (JasperFx#3351 follow-up)

PR JasperFx#3351 fixed the same tenanted-store Role defect in all five relational
providers but only added regression tests for PostgreSQL. This adds the
equivalent three-case test (ancillary single-database, ancillary with static
tenants, Main default with static tenants) to the other four providers'
test suites. All are configuration-only tests that never touch a database.

Mutation-checked on SqlServer: reverting the Role propagation in
buildMainDatabaseSettings fails both ancillary tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 10, 2026
This was referenced Jul 17, 2026
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.

2 participants