NexusSerializationContext for data/failure converters - #1828
NexusSerializationContext for data/failure converters#1828JoshuaFrenchwood wants to merge 5 commits into
Conversation
f36df7a to
0774bf3
Compare
0774bf3 to
21ee938
Compare
| self._workflow_context_failure_converter, | ||
| ) | ||
| summary_payload_converter = payload_converter | ||
| failure_converter = self._context_free_failure_converter |
There was a problem hiding this comment.
We should have a todo here. @VegetarianOrc already needs to extend this for worker callbacks.
There was a problem hiding this comment.
Added a TODO for this
There was a problem hiding this comment.
Worker callbacks are only delivered as Nexus tasks, and won't affect start nexus operation commands from a workflow.
Aside from that, is there a reason why we aren't using user_failure_converter here?
c91cfa3 to
b98ea57
Compare
b98ea57 to
117a7fd
Compare
| run_id: str | None | ||
| rpc_metadata: Mapping[str, str | bytes] | ||
| rpc_timeout: timedelta | None | ||
| result_type: type[Any] | None |
There was a problem hiding this comment.
This and the below are breaking changes that would need to be called out explicitly.
There was a problem hiding this comment.
Added this back
| async def get_nexus_operation_result( | ||
| self, input: GetNexusOperationResultInput | ||
| ) -> Any: | ||
| ) -> temporalio.api.workflowservice.v1.PollNexusOperationExecutionResponse: |
There was a problem hiding this comment.
This appears to be the only proto being exposed in the whole interceptor, it probably shouldn't be.
There was a problem hiding this comment.
It seems like the most similar thing to do like other ones would be a new object like WorkerTaskReachability or NexusOperationExecutionDescription, the latter of which similarly contains a raw proto and a dataconverter.
There was a problem hiding this comment.
Created a new object called GetNexusOperationResultOutput for this. It includes raw_result, raw_failure, and data_converter.
| ) | ||
| return await NexusOperationExecutionDescription._from_execution_info( | ||
| info=resp.info, | ||
| data_converter=self._client.data_converter, |
There was a problem hiding this comment.
Is there a reason that this dataconverter doesn't get the serialization context?
There was a problem hiding this comment.
Updated, before operation wasnt a field in GetNexusOperationResultInput, but since I added that it can create the serialization context
| cls, | ||
| info: temporalio.api.nexus.v1.NexusOperationExecutionInfo, | ||
| data_converter: temporalio.converter.DataConverter, | ||
| failure_data_converter: temporalio.converter.DataConverter | None = None, |
There was a problem hiding this comment.
I'm not sure this is necessary. I think data_converter should get the context and be used for failure conversion and elsewhere.
There was a problem hiding this comment.
Removed that, thanks
| result_type: type | None = None, | ||
| endpoint: str = "", | ||
| service: str = "", | ||
| _nexus_serialization_context: ( |
There was a problem hiding this comment.
| _nexus_serialization_context: ( | |
| nexus_serialization_context: ( |
There was a problem hiding this comment.
Removed this field
| _data_converter: DataConverter = field(repr=False, compare=False) | ||
|
|
||
|
|
||
| @dataclass | ||
| class GetNexusOperationResultOutput: | ||
| """Output for :py:meth:`OutboundInterceptor.get_nexus_operation_result`. | ||
|
|
||
| .. warning:: | ||
| This API is experimental and unstable. | ||
| """ | ||
|
|
||
| raw_result: temporalio.api.common.v1.Payload | None | ||
| """Raw result payload if the operation succeeded.""" | ||
|
|
||
| raw_failure: temporalio.api.failure.v1.Failure | None | ||
| """Raw failure if the operation failed.""" | ||
|
|
||
| data_converter: DataConverter = field(repr=False, compare=False) | ||
| """Data converter for decoding the result or failure.""" |
There was a problem hiding this comment.
I think we should consider adding endpoint, service and operation to GetNexusOperationResultInput. Then the serialization context can be created in the terminal interceptor and decoding can happen as it did previously.
Threading the data converter or context itself through and having this output type feels a bit off to me. Happy to discuss though!
There was a problem hiding this comment.
I like that approach, I updated it to have all three, endpoint/service/operation.
| The context is not propagated to the eventual result of an asynchronous operation. Standalone | ||
| operation handles use the context of their start request, including when an existing operation | ||
| is returned, while handles created without starting an operation do not receive it. |
There was a problem hiding this comment.
The first sentence here seems to belong with the section above and the part about standalone operation handles is a little hard to parse.
There was a problem hiding this comment.
Update this doc, tried to copy over what we had in the go-sdk
| Callers and handlers receive this context on opposite sides of failure conversion. Contextual | ||
| encodings should therefore be self-describing and support legacy payloads without context. |
There was a problem hiding this comment.
Maybe I'm just not seeing it, but I'm not sure what "opposite sides of failure conversion" means exactly.
| data_converter = data_converter or self._data_converter_for_nexus_task( | ||
| endpoint, start_request.service, start_request.operation | ||
| ) |
There was a problem hiding this comment.
IMO we should either make this always use self._data_converter_for_nexus_task and remove the argument or make the argument required.
There was a problem hiding this comment.
Made it required.
| self._workflow_context_failure_converter, | ||
| ) | ||
| summary_payload_converter = payload_converter | ||
| failure_converter = self._context_free_failure_converter |
There was a problem hiding this comment.
Worker callbacks are only delivered as Nexus tasks, and won't affect start nexus operation commands from a workflow.
Aside from that, is there a reason why we aren't using user_failure_converter here?
| HMAC_ENCODING = b"binary/nexus-context-hmac" | ||
| ZLIB_ENCODING = b"binary/nexus-context-zlib" | ||
| HMAC_KEY = b"nexus-context-test-key" |
There was a problem hiding this comment.
Smallish nit: Seems like we could probably prove the context usage w/o using these various encodings and using a simpler marker or something.
There was a problem hiding this comment.
Updated this to be a simpler red/blue test for two different nexus endpoint
What was changed
Added NexusSerializationContext for nexus callers and sync handlers. This allows data and failure converters to use nexus endpoint, service and operation to be used for encoding and decoding.
Why?
This enables codecs to select serialization behavior or encryption keys by Nexus endpoint, service, or operation.
For example, workflows calling two Nexus endpoints can encrypt each endpoint’s payloads with a different key while ensuring that inputs, results, and failures are decoded with the converter selected for the corresponding operation.
Checklist
Closes
How was this tested:
Added unit/functional tests to verify that NexusSerializationContext works as expected.