Repository navigation
Conversation
The workflow worker downloaded stored inputs of activities, child workflows, signals and Nexus operations that the workflow itself started, even though it never reads them. Each large activity argument was downloaded twice: once by the workflow worker and once by the activity worker. Leave those payloads as references when the workflow worker loads history. Everything else is downloaded as before.
The workflow's data converter does not download references, so a skipped payload is not fetched on demand if something reads it later. Say so, and note where to change the list of skipped events.
Make the test activity return a large result, so the test fails if the workflow worker skips downloads it needs.
A parent starts a child with a large input and signals another workflow with a large input. Each input must be downloaded only by the workflow that receives it, including when the parent's history is replayed.
Author
|
@jmaeagle99 this is related to the external storage changes and fixes a double-download issue that we saw when running on Google storage, the root cause is cloud agnostic. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed?
With external storage, the workflow worker no longer downloads stored payloads it never reads: the inputs of activities, child workflows, signals and Nexus operations that the workflow itself started. Activity workers, Nexus workers and clients still download everything as before.
Why?
Each large activity argument was downloaded twice: once by the workflow worker, which ignores it, and once by the activity worker, which needs it. When a workflow was replayed after a cache miss, the workflow worker downloaded every past argument again.
Replay matches these events by IDs and types only, so their payloads are never needed by the workflow worker.
Our workload
We run an AI agent on Temporal. On every turn, the workflow passes the whole conversation so far to an LLM activity. A conversation grows to 500k tokens, which is about 2M characters, or a 2 MB payload per activity call by the end. Payloads over the default 256 KiB threshold go to external storage, so every late turn uploads a new copy of the conversation as an activity argument.
To measure this, we ran 20-turn conversations that grow to 500k tokens, with many conversations running at once:
Other SDKs
Python doesn't have this problem
The Python SDK is built on the Rust core, and its workflow worker doesn't read history events itself. The core matches the workflow's commands against history and gives Python an activation: a list of things the workflow has to react to, such as its arguments, signals, queries, updates, and activity, child workflow and Nexus results. Python only downloads external storage payloads in that activation (
decode_activationintemporalio/bridge/worker.py). No activation job carries the inputs the workflow sent, so Python already downloads each activity argument once, which is what this change does for Java.Go has the same problem
The Go SDK's workflow worker downloads external storage payloads in every history event it receives, both in the polled workflow task (
internal/internal_task_pollers.go) and in later history pages. The only payloads it skips are search attributes (visitProtoPayloadsininternal/payload_visitor.go). So, like Java before this change, it downloads each large activity, child workflow, signal and Nexus input it sent, and downloads them all again on a cache miss. A similar fix would work there.Breaking changes?
None.
Server PR
Not required.
Testing