Skip to content

feat(client): add WorkflowClient interceptors for list and fetchHistory - #2215

Open
trippyogi wants to merge 4 commits into
temporalio:mainfrom
trippyogi:feat/client-list-fetchhistory-interceptors
Open

feat(client): add WorkflowClient interceptors for list and fetchHistory#2215
trippyogi wants to merge 4 commits into
temporalio:mainfrom
trippyogi:feat/client-list-fetchhistory-interceptors

Conversation

@trippyogi

@trippyogi trippyogi commented Jul 15, 2026

Copy link
Copy Markdown

Summary

  • Add list and fetchHistory to WorkflowClientInterceptor, with matching input types
  • Wire both through composeInterceptors (same pattern as describe / Nexus list)
  • Cover with an integration test in test-interceptors.ts

Closes #945

Test plan

  • pnpm -F @temporalio/client... run build
  • With a local Temporal server: RUN_INTEGRATION_TESTS=true pnpm -F @temporalio/test run test -- test-interceptors
  • Confirm interceptor sees list / fetchHistory calls and next() still works

Wire list and fetchHistory through composeInterceptors so client
interceptors can observe or modify those calls, matching describe and
Nexus list. Closes temporalio#945.
@trippyogi
trippyogi requested a review from a team as a code owner July 15, 2026 17:57
trippyogi and others added 2 commits July 15, 2026 11:44
…ceptors

Keep Required<WorkflowClientInterceptor> completeness after adding the new
client interceptor methods.
});
});

test.serial('WorkflowClientInterceptor intercepts list and fetchHistory', async (t) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the list() hook will need more coverage than this. The fact that it is a generator adds some complications. Plus, we'll need to test interception in the case of list().withHistories().

Let's try this. Start a few workflow executions (~10), then do for await (const _ of client.list({ /* query is not important */, pageSize: 2 })) {. That would require >5 requests to the server to see all search result. But then, in the loop, break once you've seen 3 pages, without reaching the end of the generator.

I would expect the list interceptor to have been called only once in that sequence. And given the current test implementation (interceptor function is sync), I'm pretty sure the list interceptor function will return immediately.

Does that "return immediately" behavior really what we need for list interceptors? For example, will OTel correctly figure out the encapsulation and timeline of the list call? I'm really not sure about that. My intuition is that the list interceptor would have to be a generator itself, proxying each request to the downstream AsyncIterator obtained by calling next().

Also, do the same thing with for await (const _ of client.list({ /* query is not important */, pageSize: 2 }).intoHistories()) {. In addition to the list() call, confirm that you're seeing >6 calls to fetchHistory.

@mjameswh

Copy link
Copy Markdown
Contributor

Thanks for the contribution.

Out of curiosity, do you have an actual use case requiring those specific interceptors?

One of the reasons we never prioritized that request is due to uncertainties on what granularity we'd want the list interceptor to see. My intuition is that most implementations of the list() interceptor would have to be generators, but I'm not 100% sure about that, so I'd be interested to hear expectations of real life users.

@trippyogi

Copy link
Copy Markdown
Author

Thanks for the contribution.

Out of curiosity, do you have an actual use case requiring those specific interceptors?

One of the reasons we never prioritized that request is due to uncertainties on what granularity we'd want the list interceptor to see. My intuition is that most implementations of the list() interceptor would have to be generators, but I'm not 100% sure about that, so I'd be interested to hear expectations of real life users.

Thanks, @mjameswh. I don’t have a production use case that depends on these interceptors. I opened this from #945’s completeness gap, without a defined list() granularity or a concrete consumer.

The motivating idea was observability around those client ops, but I agree the generator / multi-page semantics need to be settled before locking the API. Happy to park or close this until that’s clearer, or split out fetchHistory if you want that independently while list gets designed.

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.

[Feature Request] Add client interceptor for list and fetch_history

2 participants