You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The restate documentation specifies how handlers are to be deterministic, keeping non-deterministic operations in restate.Run or restate.Rand. This documentation doesn't mention that the codec (JSONCodec by default) must also be deterministic.
This came up with the CloudEvents SDK, which has a MarshalJSONimplementation that iterates through a stored map to add the keys/values to a JSON document. Since Go uses a randomized iteration order for maps, this means that converting CloudEvent's Event objects to JSON may result in different orderings.
If the SetExtension lines are commented out, then sometimes requests will pass, and other times they will be retried until successful. If the SetExtension lines are kept; however, there is a chance that a retry will result in the call to restate.Service using a differently ordered JSON file - causing this error:
2025/01/20 22:30:16 ERROR Journal mismatch: Replayed journal entries did not correspond to the user code. The user code has to be deterministic! method=FirstService/Handle invocationID=inv_1gdbLDeS59C52GA3G1nv6lPHPgBoN7LaHn expectedType=*wire.CallEntryMessage expectedMessage="{\"service_name\":\"SecondService\",\"handler_name\":\"Process\",\"parameter\":\"eyJzcGVjdmVyc2lvbiI6IjEuMCIsImlkIjoiMmMzNzJlY2YtNzY2Zi00MzcwLWI2YmMtZGIxNTE1M2M2OTlkIiwic291cmNlIjoiZXhhbXBsZS91cmkiLCJ0eXBlIjoiZXhhbXBsZS50eXBlIiwidGltZSI6IjIwMjUtMDEtMjFUMDQ6MzA6MTYuNTc0NTgxNzM3WiIsImUiOiJmIiwiYSI6ImIiLCJjIjoiZCJ9\",\"Result\":null}" actualType=*wire.CallEntryMessage actualMessage="{\"service_name\":\"SecondService\",\"handler_name\":\"Process\",\"parameter\":\"eyJzcGVjdmVyc2lvbiI6IjEuMCIsImlkIjoiMmMzNzJlY2YtNzY2Zi00MzcwLWI2YmMtZGIxNTE1M2M2OTlkIiwic291cmNlIjoiZXhhbXBsZS91cmkiLCJ0eXBlIjoiZXhhbXBsZS50eXBlIiwidGltZSI6IjIwMjUtMDEtMjFUMDQ6MzA6MTYuNTc0NTgxNzM3WiIsImEiOiJiIiwiYyI6ImQiLCJlIjoiZiJ9\",\"Result\":{\"Value\":\"\"}}"
Note that the only difference between these is the ordering of the e, a, or c fields.
This issue is to ask two related questions:
Is there any way to update the comparison for whats the "same" about a message to consider equivalent JSON? Perhaps by adding a mime type for the parameter in the journal message
Would there be appetite for a PR that optionally forces normalization of the JSON that goes through a codec? (e.g., arranges the fields within each nested object to be in alphabetic order). I'm not sure of a straightforward way to do that without parsing and serializing again though.
The text was updated successfully, but these errors were encountered:
Certainly it makes sense to document this requirement. I will do so
I feel a bit uncertain about allowing for byte differences in the serialised message, and indeed this requires storing some information about the nature of the data. Its quite expensive to do a more flexible equivalency check by default, imo, and would only benefit some rare edge cases
That said, I think force-normalizing JSON that goes through a codec is fine. I don't think this should be enabled by default, but it would be easy to have a user-provided codec which does this, or it could be a non-default JSON codec thats bundled with the library. Indeed, the only way I can think of doing it is to parse into a interface{} and then reserialise, which will be pretty slow :(. Maybe there is some fancy json library that could do it faster
The restate documentation specifies how handlers are to be deterministic, keeping non-deterministic operations in
restate.Run
orrestate.Rand
. This documentation doesn't mention that the codec (JSONCodec by default) must also be deterministic.This came up with the CloudEvents SDK, which has a
MarshalJSON
implementation that iterates through a stored map to add the keys/values to a JSON document. Since Go uses a randomized iteration order for maps, this means that converting CloudEvent'sEvent
objects to JSON may result in different orderings.This is reproducible with the following code:
If the
SetExtension
lines are commented out, then sometimes requests will pass, and other times they will be retried until successful. If theSetExtension
lines are kept; however, there is a chance that a retry will result in the call torestate.Service
using a differently ordered JSON file - causing this error:The expected parameter of this call are:
while the actual parameters are:
Note that the only difference between these is the ordering of the
e
,a
, orc
fields.This issue is to ask two related questions:
The text was updated successfully, but these errors were encountered: