mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed - Replaced per-key trailer format with a single protobuf `ContextMetadata` message serialized into `contextmetadata-bin` trailer key - gRPC automatically base64-encodes the `-bin` value, making arbitrary bytes (including HTTP/2-unsafe control chars) transport-safe - Writer emits both proto format and legacy per-key format for backward compatibility during rolling deploys - Reader prefers proto key, falls back to legacy per-key format for old writers - Wired `TrailerToContextMetadataInterceptor` in test server to match production behavior ## Why Workflow type names containing control characters (newlines, NUL, etc.) cause the gRPC HTTP/2 framer to reject trailer values. A single proto message in a `-bin` key is simpler than per-key `-bin` suffixes: one trailer key, one serialization, no key naming constraints, cleaner backward compat removal. ## How tested - Unit tests for proto round-trip, dual-format emission, reader preference, legacy fallback, HTTP/2 safety - Integration test suite (TestWorkflowTypeEncodingSuite) with control chars, UTF-8, long names, -bin suffix workflow types - All existing tests pass ## Risks - During rolling deploy, old writers emit only legacy keys. New readers handle this via fallback path. No data loss. - After full rollout, legacy key emission can be removed in a follow-up. --- > [!NOTE] > **Medium Risk** > Changes how context metadata is encoded/decoded in gRPC trailers, which can affect cross-version compatibility and observability of propagated metadata. Backward-compatible legacy fallback and extensive unit/integration tests reduce the rollout risk. > > **Overview** > **Switches context-metadata propagation in gRPC trailers to a single proto-encoded payload.** Server-side `ContextMetadataInterceptor` now serializes all context metadata into a new `ContextMetadata` protobuf and emits it under `contextmetadata-bin`, avoiding HTTP/2-unsafe control characters in values. > > **Maintains rolling-deploy compatibility.** Writers still emit legacy per-key trailers (skipping unsafe values), and the client-side `TrailerToContextMetadataInterceptor` now *prefers* the proto trailer and falls back to legacy keys (including unprefixed well-known keys) when needed. > > Adds the new `contextpropagation/v1` proto + generated Go types, plus unit tests around proto/legacy behavior and an integration suite (`WorkflowTypeEncodingSuite`) covering control characters, UTF-8, long names, and `-bin` suffix workflow types. > > <sup>Reviewed by [Cursor Bugbot]() for commit e1d772fc3fe8e136fded479415f8f049ac896054. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> --------- Co-authored-by: Hanzo Dev <[email protected]>
44 lines
1.1 KiB
Go
44 lines
1.1 KiB
Go
// Code generated by protoc-gen-go-helpers. DO NOT EDIT.
|
|
package contextpropagation
|
|
|
|
import (
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
// Marshal an object of type ContextMetadata to the protobuf v3 wire format
|
|
func (val *ContextMetadata) Marshal() ([]byte, error) {
|
|
return proto.Marshal(val)
|
|
}
|
|
|
|
// Unmarshal an object of type ContextMetadata from the protobuf v3 wire format
|
|
func (val *ContextMetadata) Unmarshal(buf []byte) error {
|
|
return proto.Unmarshal(buf, val)
|
|
}
|
|
|
|
// Size returns the size of the object, in bytes, once serialized
|
|
func (val *ContextMetadata) Size() int {
|
|
return proto.Size(val)
|
|
}
|
|
|
|
// Equal returns whether two ContextMetadata values are equivalent by recursively
|
|
// comparing the message's fields.
|
|
// For more information see the documentation for
|
|
// https://pkg.go.dev/google.golang.org/protobuf/proto#Equal
|
|
func (this *ContextMetadata) Equal(that interface{}) bool {
|
|
if that == nil {
|
|
return this == nil
|
|
}
|
|
|
|
var that1 *ContextMetadata
|
|
switch t := that.(type) {
|
|
case *ContextMetadata:
|
|
that1 = t
|
|
case ContextMetadata:
|
|
that1 = &t
|
|
default:
|
|
return false
|
|
}
|
|
|
|
return proto.Equal(this, that1)
|
|
}
|