Skip to content

💥 Use ExternalStorageReference protobuf message for payload references#2311

Open
jmaeagle99 wants to merge 1 commit intotemporalio:mainfrom
jmaeagle99:storage-ref-proto
Open

💥 Use ExternalStorageReference protobuf message for payload references#2311
jmaeagle99 wants to merge 1 commit intotemporalio:mainfrom
jmaeagle99:storage-ref-proto

Conversation

@jmaeagle99
Copy link
Copy Markdown
Contributor

What was changed

  • Store and retrieve payload references as ExternalStorageReference protobuf message encoded with protojson.
  • Allow backward compatible retrieval of prerelease plain json encoding.
  • Embed ExternalStorageReference proto message definition in sdk-go until api-go contains the same definition. Generate structure and data such that wire format and data are exactly the same as would be in api-go.

Why?

  • Standardize on protobuf message for encoding storage references.

Checklist

  1. How was this tested: Existing tests, compat tests, and new tests
  2. Any docs updates needed? No

@jmaeagle99 jmaeagle99 marked this pull request as ready for review April 28, 2026 16:37
@jmaeagle99 jmaeagle99 requested a review from a team as a code owner April 28, 2026 16:37
@yuandrew
Copy link
Copy Markdown
Contributor

For reference, this is the API PR: temporalio/api#772

type storageReference struct {
// legacyStorageReference is the old wire format retained for backward compatibility
// with payloads written by earlier prerelease SDK versions.
type legacyStorageReference struct {
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.

Why do we want/need to maintain the earlier prerelease SDK version? Since it's still in prerelease, should we just make the breaking change here, so we only need to support one format?

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 guess we maybe don't want to completely break previous workflows, but do we plan on deprecating this legacy stuff before we hit public preview/GA?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We don't want to immediately break anyone who used the prerelease bits. We'll remove before GA.

// payloads that are storage references rather than actual data.
const metadataEncodingStorageRef = "json/external-storage-reference"
// metadataMessageType is the key used in payload metadata to identify the proto
// message type. Mirrors converter.MetadataMessageType without importing converter package.
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: Do we want to add a mirroring comment to converter.MetadataMessageType that it matches this new value? Same question for metadataEncodingProtoJSON

]
}`

externalStorageReferenceMessageType = string((*sdkpb.ExternalStorageReference)(nil).ProtoReflect().Descriptor().FullName())
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 this line needed? Don't we already set this value in internal_extstore.go?

// IsStorageReference reports whether p is an external-storage reference payload
// (i.e. its encoding metadata equals the internal storage-reference marker).
// IsStorageReference reports whether p is an external-storage reference payload.
// It recognises both the current protojson format (encoding=json/protobuf,
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: recognises is the british form of recognizes? Not sure we use British spelling elsewhere in the SDK. I know we use Canadian forms of words (i.e. Behaviour), but not aware of any british spelling, haha

Suggested change
// It recognises both the current protojson format (encoding=json/protobuf,
// It recognizes both the current protojson format (encoding=json/protobuf,

@@ -0,0 +1,39 @@
# internal/temporalapi
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.

Any reason we need this over waiting for an API release to ingest the changes from there?


// metadataEncodingProtoJSON is the standard protojson encoding value, shared with
// ProtoJSONPayloadConverter. Mirrors converter.MetadataEncodingProtoJSON.
const metadataEncodingProtoJSON = "json/protobuf"
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.

technically this is breaking if we use an old SDK to read the new deployment format for a rolling deployment. A safer pattern would be to introduce the new format but continue to use the old, then a version later switch to the new format by default. But I assume we don't have time for this multi-release rollout. I'm fine without it, but not sure if we want to add a 💥 . It's a bit of an edge case

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added boom to title

externalStorageReferenceMessageType = string((*sdkpb.ExternalStorageReference)(nil).ProtoReflect().Descriptor().FullName())

protoMarshalOptions = protojson.MarshalOptions{}
protoUnmarshalOptions = protojson.UnmarshalOptions{}
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.

Do we want to have DiscardUnknown: true? For if an older SDK version tries to read a payload from a new SDK that added a new field to ExternalStorageReference

https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson#UnmarshalOptions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Wouldn't we have had to add that option to the plain JSON converter in the old SDK though to work with the scenario that you outlined?

// TestClaimDeserialization_OtherSdk_ProtoJson verifies that a full proto-JSON
// payload produced by another language SDK (e.g. Python) is correctly parsed by
// the Go SDK's payloadToStorageReference function.
func TestClaimDeserialization_OtherSdk_ProtoJson(t *testing.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.

JSON in ProtoJson should be all caps, same with PlainJson

@jmaeagle99 jmaeagle99 changed the title Use ExternalStorageReference protobuf message for payload references 💥 Use ExternalStorageReference protobuf message for payload references Apr 28, 2026
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.

2 participants