Skip to content

Query saga instances by saga type: filters, ordering and counts across saga storages #5296

Closed

Description

@jeremydmiller

Goal

Let a monitoring tool query saga instances for one saga type, with filters on the saga's own properties, ordering, paging and a total count, through one abstraction across every saga storage.

The question this answers is the one an operator has with a stuck workflow: "which OrderSaga instances are in AwaitingPayment and have not changed for two days?" CritterWatch already offers exactly this for documents through IDocumentStoreDiagnostics, and wants the same for sagas.

What exists

ISagaStoreDiagnostics has GetRegisteredSagasAsync, ReadSagaAsync and ListSagaInstancesAsync(sagaTypeName, count), aggregated through IWolverineRuntime.SagaStorage.

Two limits:

  1. ListSagaInstancesAsync is a bounded sample, not a query. It has no filter and no count.
  2. It has no defined order. The Marten, EF Core and RavenDB implementations are Query<TSaga>().Take(count) with no OrderBy, so which instances come back is up to the database. Nothing can honestly call them recent. Whatever this issue decides, the ordering should be defined and documented.

Proposal

Add a query method to the saga storage abstraction, default-implemented so existing storages still load, plus a statement of what each storage can do:

Task<SagaQueryResult> QuerySagasAsync(
    string sagaTypeName, DocumentQueryOptions options, CancellationToken ct);

Reuse JasperFx's DocumentQueryOptions rather than inventing a second shape. DocumentQueryCriteria.ApplyCriteriaTo<T>(IQueryable<T>) already turns a Where and OrderBy string into dynamic LINQ on any IQueryable<T>, and IsTranslationFailure already recognises a provider refusing a clause. So any storage with a real IQueryable<TSaga> should get this for very little code:

Storage Read today Querying
Marten, Polecat, Fisher Yes Query<TSaga>() plus ApplyCriteriaTo, or forward to the store's IDocumentStoreDiagnostics, since a saga is a document there
EF Core Yes Set<TSaga>().AsNoTracking() plus ApplyCriteriaTo
RavenDB Yes Query<TSaga>() plus ApplyCriteriaTo; needs a look at which clauses Raven's provider refuses
Lightweight (PostgreSQL, SQL Server, MySQL, Oracle, SQLite, through DatabaseSagaStoreDiagnostics) Yes No IQueryable, and the saga is a JSON body. Probably paging and ordering only, with a filter refused
CosmosDB No ISagaStoreDiagnostics implementation in 6.59.1 Needs read support as well as querying

The name is open: this could be a new "saga storage provider" concept that ISagaStoreDiagnostics becomes part of, or an extension of that interface.

Rules

  • Refuse rather than answer wrongly. A storage that cannot honour a Where throws, as IDocumentStoreDiagnostics.QueryDocumentsAsync must. It never returns an unfiltered page.
  • Say what is supported. A caller needs to know up front whether a storage can filter, so a UI offers only what works.
  • Results carry a total count, and the page size is clamped.
  • DocumentQueryCriteria.IsAvailable is false where dynamic code is not supported, so the AOT case refuses cleanly.

Order of work

Marten, Polecat and Fisher first, since those are nearly free, then EF Core and RavenDB, then lightweight and CosmosDB. Each storage is useful alone.

Related question

A saga declares no named states today. If a saga could mark a member as its status, tools could show real states instead of inferring them from messages. That is a separate decision and is not required here.

Activity

  1. added a commit that references this issue on Oct 30, 2026
  2. added a commit that references this issue on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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