Skip to content

feat(#4962): targeted per-cell ReadProjectionProgressAsync on MartenDatabase#4974

Merged
jeremydmiller merged 1 commit into
masterfrom
feature/4962-read-projection-progress
Jul 17, 2026
Merged

feat(#4962): targeted per-cell ReadProjectionProgressAsync on MartenDatabase#4974
jeremydmiller merged 1 commit into
masterfrom
feature/4962-read-projection-progress

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

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 through AllProjectionProgress.

Resolution semantics

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):

  • Candidates = rows whose parsed ShardName.Name == projectionName and parsed TenantId == tenantId.
  • tenantId == null matches only bare store-global rows (no tenant suffix).
  • Multiple matches (a blue/green deploy) → newest Version wins, tie-broken on the highest sequence.
  • No match → null.
  • AgentStatus / LastHeartbeat → always null (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"; final Name/Tenant matching is exact on the parsed ShardName.

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 ShardName should be able to skip this collapsing via an exact overload — tracked separately (a new JasperFx ReadProjectionProgressAsync(ShardName, …) member + Marten/Polecat adoption).

Closes #4962.

🤖 Generated with Claude Code

…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
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.

Implement IEventDatabase.ReadProjectionProgressAsync against mt_event_progression (jasperfx#435)

1 participant