feat(#4962): targeted per-cell ReadProjectionProgressAsync on MartenDatabase#4974
Merged
Merged
Conversation
…atabase Override the #435 default-throwing IEventDatabase.ReadProjectionProgressAsync so a monitoring tool can poll a single (projection, tenant) progression cell without fetching + filtering every row via AllProjectionProgress. mt_event_progression.name holds a full ShardName.Identity, so one projection name can map to several rows (blue/green versions, custom shard keys, per-tenant partitions). Resolution: candidates are rows whose parsed ShardName.Name equals projectionName and whose parsed TenantId equals tenantId — a null tenantId matches ONLY the bare store-global rows (no tenant suffix); when several match (a blue/green deploy) the NEWEST version wins, tie-broken on the highest sequence; no match returns null. AgentStatus and LastHeartbeat are always null (Marten models the columns but no daemon path writes them — #519). The name LIKE 'projectionName:%' probe leans on the ':' delimiter so "Orders" cannot match "OrdersHistory"; final Name/Tenant matching is exact on the parsed ShardName. Callers that already hold a full ShardName (e.g. from AllProjectionProgress) will be able to avoid this collapsing once the exact ShardName overload lands (follow-up). Closes #4962. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKKBPsFJ83jd2o4hyGJnj6
This was referenced Jul 18, 2026
Open
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.
Overrides the jasperfx#435 default-throwing
IEventDatabase.ReadProjectionProgressAsync(string projectionName, string? tenantId, …)so a monitoring tool (CritterWatch) can poll a single(projection, tenant)progression cell without fetching and filtering every row throughAllProjectionProgress.Resolution semantics
mt_event_progression.nameholds a fullShardName.Identity, so one projection name can map to several rows (blue/green versions, custom shard keys, per-tenant partitions):ShardName.Name == projectionNameand parsedTenantId == tenantId.tenantId == nullmatches only bare store-global rows (no tenant suffix).Versionwins, tie-broken on the highest sequence.null.AgentStatus/LastHeartbeat→ alwaysnull(Marten models the columns but no daemon path writes them — Create duplicate field index #519).The
name LIKE 'projectionName:%'probe leans on the:delimiter so"Orders"can't match"OrdersHistory"; finalName/Tenantmatching is exact on the parsedShardName.Tests
DaemonTests/Internals/read_projection_progress.cs(5): store-global read, null-when-absent, newest-version-wins across a blue/green deploy, null-tenant-matches-only-bare-global, and the prefix guard.Follow-up
Callers that already hold a full
ShardNameshould be able to skip this collapsing via an exact overload — tracked separately (a new JasperFxReadProjectionProgressAsync(ShardName, …)member + Marten/Polecat adoption).Closes #4962.
🤖 Generated with Claude Code