Repository navigation
GH-5002 The leader's heartbeat reads shard names and databases, not the full event store usage - #5011
Merged
Merged
Conversation
…he full event store usage EventStoreAgents.SupportedAgentsAsync runs on every leader heartbeat for every store. It built the whole EventStoreUsage descriptor (the highest event sequence, and every projection, subscription, event type and tag type) for the async shard names and the database topology alone. - Async shard names come from IEventStore.RegisteredShardNames(), the store's in-memory registry. It is the same set: async projections plus subscriptions, which always report Async. A store that doesn't implement it falls back to the usage. - The database topology comes from the new IEventStore.TryDescribeDatabasesAsync() (JasperFx 2.87.1). The tenant-to-database lookup, StartAllAsync and AllDaemonsAsync use it too. The registered-projection rebuild keeps the full usage, because it matches Inline and Live projections as well. - JasperFx family 2.87.1. The saving is complete with Marten 9.50.1, Polecat 5.40.1 and Fisher 1.20.2, which answer it straight from their tenancy; older store versions fall back to TryCreateUsage inside the default member. - Tests: fake stores go through a shared StubUsage helper (NSubstitute intercepts default interface members too), an evaluation is pinned to never build the full usage, and a store without a shard registry still answers through the usage. Closes #5002 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 13, 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.
Closes #5002. Reported downstream by @uniquelau in JasperFx/marten#5652.
EventStoreAgents.SupportedAgentsAsyncruns on every leader heartbeat (HealthCheckPollingTime, 10 seconds by default) for every registered store. It built the wholeEventStoreUsagedescriptor, which reads the highest event sequence and describes every projection, subscription, event type and tag type.The issue says only
usage.Subscriptionsis used. That isn't quite right: the method also needs each database's server, database name and tenant ids, which drive the per-tenant agent fan-out. So this uses two narrower reads:IEventStore.RegisteredShardNames(), the store's in-memory registry, with no database work. It returns the same set the usage path produced: async projections plus every subscription, and subscriptions always reportAsync. A store that doesn't implement it falls back to the usage.IEventStore.TryDescribeDatabasesAsync()from JasperFx 2.87.1 (IEventStore.TryDescribeDatabasesAsync: the database half of TryCreateUsage (wolverine#5002) jasperfx#1013). The tenant-to-database lookup,StartAllAsyncandAllDaemonsAsyncuse it too.Where the saving comes from
TryDescribeDatabasesAsync()is a default interface member that falls back toTryCreateUsage()?.Database. With the store versions Wolverine currently pins, this is correct but saves nothing yet. The saving is complete with Marten 9.50.1, Polecat 5.40.1 and Fisher 1.20.2, which override it to answer from their tenancy. Those releases are on their way, and an application can take them directly.Tests
StubUsagehelper. NSubstitute intercepts default interface members too, so stubbing onlyTryCreateUsagewould leave the new reads answering null and an empty list. This includes the test GH-5003 Resume continuous execution after a projection rebuild, even a failed one #5008 added.an_evaluation_builds_each_stores_usage_oncenow also asserts that an evaluation never callsTryCreateUsage.a_store_without_a_shard_registry_still_answers_its_shards_through_the_usage.Verification
dotnet build wolverine.slnx -c Release -f net9.0against JasperFx 2.87.1: clean.CoreTests.Runtime.Agents(net9.0): 486 passed, 6 skipped, 0 failed.MartenTests.Distributionagainst local Postgres: 49 of 49 passed.🤖 Generated with Claude Code