Lokasi ngalangkungan proxy:   [ UP ]  
[Ngawartoskeun bug]   [Panyetelan cookie]                
Skip to content

feat(critterwatch): polecat outbox listener fix + DocumentStores capability surface#2672

Merged
jeremydmiller merged 1 commit intomainfrom
polecat-fix-and-document-stores-capabilities
May 4, 2026
Merged

feat(critterwatch): polecat outbox listener fix + DocumentStores capability surface#2672
jeremydmiller merged 1 commit intomainfrom
polecat-fix-and-document-stores-capabilities

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Two CritterWatch-facing changes plus the dependency bumps they need.

1. fix(polecat) — GH-2668

OutboxedSessionFactory.buildSessionOptions was constructing the FlushOutgoingMessagesOnCommit listener with null! for the SqlServerMessageStore on the assumption that a post-construction setter would fill it in — but the listener's field is readonly and no such setter exists. The first read of _messageStore.Role NRE'd, killing every Polecat-backed Wolverine handler that traversed the durable inbox (e.g. PolecatTrips in CritterWatch's BffHost).

Direct cast to SqlServerMessageStore covers the simple case but throws InvalidCastException when runtime.Storage is a MultiTenantedMessageStore wrapping the SQL-Server-backed root. Added resolveSqlServerMessageStore() that mirrors PolecatEnvelopeTransaction's existing two-shape resolution (SqlServerMessageStore | MultiTenantedMessageStore { Main: SqlServerMessageStore }) and throws a clear InvalidOperationException if the runtime isn't SQL-Server-backed at all.

Coverage gap that let the bug ship: no PolecatTests test exercised the OutboxedSessionFactory listener path. Existing tests use InvokeMessageAndWaitAsync against non-durable defaults, which leaves Envelope.WasPersistedInInbox false and short-circuits the listener's interesting branch. The new PolecatTests/Bugs/Bug_2668_outboxed_session_listener_null_message_store.cs wires UseDurableLocalQueues + SendMessageAndWaitAsync so the local queue persists the envelope before the handler runs (flipping WasPersistedInInbox to true), and asserts the document the handler stores actually lands. With the bug present the handler NREs in SaveChangesAsync and the document never persists; with the fix the round-trip completes.

2. feat(capabilities) — DocumentStores list on ServiceCapabilities

Mirrors the existing readEventStores walk for the document side. Walks IDocumentStoreUsageSource registrations (Marten and Polecat both implement it via IDocumentStore), dedupes by Subject URI to avoid double-counting when the same instance wears both event-store and document-store hats, and stuffs DocumentStoreUsage snapshots into the capabilities surface so CritterWatch can render document-side config the same way it already renders event stores. Stores that fail transient init are silently skipped — same permissive policy as the event-store path.

3. chore(deps) — JasperFx 1.28.2 → 1.29.0, JasperFx.Events 1.31.1 → 1.33.1, Marten + Marten.AspNetCore 8.32.0 → 8.35.0

IDocumentStoreUsageSource and DocumentStoreUsage live in the bumped JasperFx packages; the Marten bump tracks the latest version that ships the corresponding source-side wiring.

Test plan

🤖 Generated with Claude Code

…bility surface

Two CritterWatch-facing changes:

1. fix(polecat): wire SqlServerMessageStore into FlushOutgoingMessagesOnCommit
   GH-2668. OutboxedSessionFactory.buildSessionOptions used to pass `null!`
   for the SqlServerMessageStore on the assumption that a post-construction
   setter would fill it in — but the listener's field is readonly and no
   such setter exists. The first read of `_messageStore.Role` NRE'd, killing
   every Polecat-backed Wolverine handler that traversed the durable inbox
   (e.g. PolecatTrips in CritterWatch's BffHost).

   Direct cast to SqlServerMessageStore covers the simple case but throws
   InvalidCastException when runtime.Storage is a MultiTenantedMessageStore
   wrapping the SQL Server-backed root. Added resolveSqlServerMessageStore()
   that mirrors PolecatEnvelopeTransaction's existing two-shape resolution
   (SqlServerMessageStore | MultiTenantedMessageStore { Main: SqlServerMessageStore })
   and throws a clear InvalidOperationException if the runtime isn't
   SQL-Server-backed at all.

   Coverage gap that let the bug ship: no PolecatTests test exercised the
   OutboxedSessionFactory listener path. Existing tests use
   InvokeMessageAndWaitAsync against non-durable defaults, which leaves
   Envelope.WasPersistedInInbox false and short-circuits the listener's
   interesting branch. The new
   PolecatTests/Bugs/Bug_2668_outboxed_session_listener_null_message_store.cs
   wires UseDurableLocalQueues + SendMessageAndWaitAsync so the local queue
   persists the envelope before the handler runs (flipping
   WasPersistedInInbox to true), and asserts the document the handler stores
   actually lands. With the bug the handler NREs in SaveChangesAsync and
   the document never persists; with the fix the round-trip completes.

2. feat(capabilities): expose DocumentStores list on ServiceCapabilities
   Mirrors the existing readEventStores walk for the document side. Walks
   IDocumentStoreUsageSource registrations (Marten and Polecat both
   implement it via IDocumentStore), dedupes by Subject URI to avoid
   double-counting when the same instance wears both event-store and
   document-store hats, and stuffs DocumentStoreUsage snapshots into the
   capabilities surface so CritterWatch can render document-side config
   the same way it already renders event stores. Stores that fail
   transient init are silently skipped — same permissive policy as the
   event-store path.

3. chore(deps): bump JasperFx 1.28.2 -> 1.29.0, JasperFx.Events 1.31.1 ->
   1.33.1, Marten + Marten.AspNetCore 8.32.0 -> 8.35.0
   IDocumentStoreUsageSource and DocumentStoreUsage live in the bumped
   JasperFx packages; the Marten bump tracks the latest version that ships
   the corresponding source-side wiring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit f2d3416 into main May 4, 2026
21 checks passed
jeremydmiller added a commit that referenced this pull request May 4, 2026
Minor release. Highlights:

- WolverineFx.Marten: durable local messages routed by the receiving handler's
  ancillary store (Uri-based gate, no IMessageStore.Id dependency). Closes #2669.
  PR #2674.
- WolverineFx.RabbitMQ: public AddClusterNode(...) API for multi-node failover.
  Closes #2659. PR #2664.
- WolverineFx.Polecat: fixed NRE in OutboxedSessionFactory when constructing the
  FlushOutgoingMessagesOnCommit listener. Closes #2668. PR #2672.
- WolverineFx core: new DocumentStores collection on ServiceCapabilities for
  CritterWatch document-side rendering.
- Dependency bumps: JasperFx 1.28.2 → 1.29.0, JasperFx.Events 1.31.1 → 1.33.1,
  Marten + Marten.AspNetCore 8.32.0 → 8.35.0.

Also backfilled a 5.36.2 entry in CHANGELOG covering the EF Core + outbox flush
rework from PR #2665 that landed without a CHANGELOG note at the time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant