Skip to content

Implement the tenant-scoped IEventStore explorer read overrides that still throw (ReadStreamAsync / GetRecentStreamsAsync) #5019

Description

@jeremydmiller

Summary

Marten implements the tenant-scoped IEventStore.GetProjectionStatusesAsync(string? tenantId, ct) explorer overload (#4596 / #502), but two sibling tenant-scoped read overloads from #503 are not overridden and fall through to the JasperFx default that throws for a non-null tenant:

  • IEventStore.ReadStreamAsync(string streamId, string? tenantId, CancellationToken ct)
  • IEventStore.GetRecentStreamsAsync(int count, string? tenantId, CancellationToken ct)

(Confirmed by reflection against the released Marten 9.17.1 / JasperFx.Events 2.32.0: GetInterfaceMap shows both resolving to the interface default, i.e. "throws non-null tenant".) GetStreamMetadataAsync(streamId, tenantId, ct) should be checked/implemented for parity as well.

Why

On a conjoined multi-tenant store the same stream id can exist under two tenants; the tenant-less ReadStreamAsync reads across every tenant and returns their ambiguous union. CritterWatch's Event Store Explorer (CritterWatch #782) threads a tenantId through and calls these overloads to isolate a single tenant's slice — but today a picked tenant just throws.

Approach (proven locally, all 16 explorer tests + 2 new isolation tests green)

Both IEventStore read impls in src/Marten/DocumentStore.EventStoreExplorer.cs already select … tenant_id over an AllowAnyTenant explorer session, so the tenant-scoped overloads mirror the two-model shape the existing GetProjectionStatusesAsync(tenantId) uses (#502):

  • Single database (conjoined tenancy): scope with a where tenant_id = @tenant_id predicate on the same AllowAnyTenant session.
  • Database-per-tenant / sharded (Options.Tenancy.Cardinality != DatabaseCardinality.Single): open the session against Tenancy.FindOrCreateDatabase(tenantId); no column filter needed.
  • null tenant → delegate to the existing tenant-less overload (byte-identical to today).

The tenant-less overloads become thin delegators to the new tenant overloads with tenantId: null.

I have a ready patch (diff against tag V9.17.0, where the explorer file matches the release; note the current fix/4918 branch is on an older JasperFx pin that predates #503's interface overloads) — happy to open a PR.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions