Skip to content

Experimental: External Payload Storage#1341

Merged
jmaeagle99 merged 47 commits into
temporalio:mainfrom
jmaeagle99:extstore
Mar 17, 2026
Merged

Experimental: External Payload Storage#1341
jmaeagle99 merged 47 commits into
temporalio:mainfrom
jmaeagle99:extstore

Conversation

@jmaeagle99
Copy link
Copy Markdown
Contributor

@jmaeagle99 jmaeagle99 commented Feb 26, 2026

What was changed

Add external storage APIs to allow customers to specify how large payloads or payloads that match some specific customer-defined quality can be stored via customer-supplied external storage systems.

  • Customers can choose their external storage endpoints by providing storage drivers. They can either use prebuilt ones or write their own via the StorageDriver type. This change does not contain any prebuilt drivers, just provides the primitives to make them.
  • Customers can register several storage drivers. This allows workflows and clients to be able to retrieve payloads that have been stored by different driver types.
  • Customers can dynamically choose which driver to use for storing each payload by specifying a driver selector. The selector can be a simple callable or could be a StorageDriverSelector to participate in serialization context transforms.
  • External storage is situated outside of the workflow sandbox and runs after encoding for outbound requests and runs before decoding for inbound responses.
  • External storage is off by default and must be opted into via specifying DataConverter.external_storage. There are no breaking changes regardless of opted into or not.

Why?

  • Allow customers to mitigate situations where payload size may be too large to store into temporal history.
  • Allow customers to externally store payloads based on other payload and contextual qualities such a serialization context and payload metadata.

Checklist

  1. Closes External Payload Storage Foundation - Python #1342
  2. How was this tested: Add additional unit and workflow tests.
  3. Any docs updates needed? Yes, new docs for external storage should be created.

@jmaeagle99 jmaeagle99 changed the title Experimental: External Storage API Experimental: External Payload Storage API Feb 26, 2026
@jmaeagle99 jmaeagle99 force-pushed the extstore branch 4 times, most recently from f220f74 to eeba791 Compare February 26, 2026 20:09
@jmaeagle99 jmaeagle99 changed the title Experimental: External Payload Storage API Experimental: External Payload Storage Feb 26, 2026
@jmaeagle99 jmaeagle99 marked this pull request as ready for review February 26, 2026 20:23
@jmaeagle99 jmaeagle99 requested a review from a team as a code owner February 26, 2026 20:23
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/converter.py Outdated
Comment thread temporalio/extstore.py Outdated
Comment thread temporalio/extstore.py Outdated
Comment thread temporalio/extstore.py Outdated
Comment thread temporalio/extstore.py Outdated
Comment thread temporalio/extstore.py Outdated
Comment thread temporalio/extstore.py Outdated
@jmaeagle99 jmaeagle99 requested a review from tconley1428 March 13, 2026 21:02
Copy link
Copy Markdown
Contributor

@drewhoskins-temporal drewhoskins-temporal left a comment

Choose a reason for hiding this comment

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

Very excited! One important comment (which we already covered in our afternoon sync) and a bunch of polish suggestions.

Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread temporalio/converter/_extstore.py Outdated
Comment thread temporalio/converter/_extstore.py Outdated
Comment thread temporalio/converter/_extstore.py Outdated
Comment thread temporalio/converter/_extstore.py Outdated
Comment thread tests/test_extstore.py Outdated

assert isinstance(err.value.cause, ActivityError)
assert isinstance(err.value.cause.cause, ApplicationError)
assert err.value.cause.cause.message == "Failed decoding arguments"
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.

Is there enough information here for users to understand and debug what happened? I'm not seeing it here.

assert isinstance(err.value.cause.cause, ApplicationError)
assert (
err.value.cause.cause.message
== "Driver 'bad-driver' returned 0 claims, expected 1"
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.

Suggested change
== "Driver 'bad-driver' returned 0 claims, expected 1"
== "ExternalStorageDriver 'bad-driver' returned 0 claims, expected 1."

Here and on other diagnostics, please make sure to set context and to make it actionable.

  • Context. What can't we do because this happened? "Cannot store a reference to uploaded payload." or something.
  • Actionability. What should the user do to debug/fix? I'm guessing in this case it'd be "This is probably a bug in the ExternalStorageDriver."

task_queue=worker.task_queue,
)

await assert_task_fail_eventually(handle)
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.

Can we assert the message here? And as above, make sure we make an actionable suggestion for the user.

return []
if self._raise_payload_not_found:
raise ApplicationError(
"Payload not found because the bucket does not exist.",
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.

nit: I know this is just test code, but should echo the bad data (bucket ID) in the error message or its metadata.

@jmaeagle99 jmaeagle99 merged commit bb44cb8 into temporalio:main Mar 17, 2026
36 of 39 checks passed
@jmaeagle99 jmaeagle99 deleted the extstore branch March 17, 2026 01:47
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.

External Payload Storage Foundation - Python

4 participants