Skip to content

Commit ffa5c21

Browse files
authored
Support non-deterministic codecs via PayloadOptions (#122)
* fix: use unstable payload option for protojson codec * refactor: rename is_unstable -> is_non_deterministic * refactor: use unstable_serialization on the WASM level * chore: format code * chore: remove go cache
1 parent 1df111e commit ffa5c21

File tree

16 files changed

+521
-280
lines changed

16 files changed

+521
-280
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
test_report
22
.restate
3+
shared-core/pkg/

encoding/encoding.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,23 @@ type PayloadCodec interface {
122122
Codec
123123
}
124124

125+
// NonDeterministicSerializer is an interface that codecs can implement to indicate
126+
// they may produce non-deterministic output for the same input.
127+
type NonDeterministicSerializer interface {
128+
IsNonDeterministic() bool
129+
}
130+
131+
// IsNonDeterministicSerialization returns true if the codec may produce non-deterministic output.
132+
// This is true for ProtoJSONCodec (protojson does not guarantee deterministic output)
133+
// and any codec implementing NonDeterministicSerializer that returns true from IsNonDeterministic().
134+
func IsNonDeterministicSerialization(codec Codec) bool {
135+
if nonDeterministic, ok := codec.(NonDeterministicSerializer); ok {
136+
return nonDeterministic.IsNonDeterministic()
137+
}
138+
139+
return false
140+
}
141+
125142
// InputPayload is provided to Restate upon handler discovery, to teach the ingress how to validate incoming
126143
// request bodies.
127144
type InputPayload struct {
@@ -228,6 +245,12 @@ func (p protoCodec) Marshal(output any) (data []byte, err error) {
228245

229246
type protoJSONCodec struct{}
230247

248+
func (j protoJSONCodec) IsNonDeterministic() bool {
249+
// protojson does not guarantee deterministic output:
250+
// https://github.com/golang/protobuf/issues/1373
251+
return true
252+
}
253+
231254
func (j protoJSONCodec) generateProtoJsonSchema(v any) interface{} {
232255
_, msgOk := v.(protoreflect.ProtoMessage)
233256
if !msgOk {

encoding/encoding_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,23 @@ func TestGenerateJsonSchema(t *testing.T) {
9595
})
9696
}
9797
}
98+
99+
func TestIsNonDeterministicSerialization(t *testing.T) {
100+
tests := []struct {
101+
name string
102+
codec Codec
103+
expected bool
104+
}{
105+
{"JSONCodec", JSONCodec, false},
106+
{"ProtoCodec", ProtoCodec, false},
107+
{"ProtoJSONCodec", ProtoJSONCodec, true},
108+
{"BinaryCodec", BinaryCodec, false},
109+
}
110+
111+
for _, tt := range tests {
112+
t.Run(tt.name, func(t *testing.T) {
113+
result := IsNonDeterministicSerialization(tt.codec)
114+
require.Equal(t, tt.expected, result, "IsNonDeterministicSerialization(%s) = %v, want %v", tt.name, result, tt.expected)
115+
})
116+
}
117+
}

0 commit comments

Comments
 (0)