Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: Support returning json serializable objects from an orchestrator function #490

Merged
merged 2 commits into from
Mar 15, 2024

Conversation

ZainRizvi
Copy link
Contributor

@ZainRizvi ZainRizvi commented Mar 9, 2024

Currently you can send an arbitrary json-serializable to a sub orchestrator, but that sub orchestrator cannot return the same object.

This because the input param's serializer falls back to using a generic custom obj serializer, but the orchestrator return value doesn't get the same special treatment.

Fixes in this PR

  • Pass in the same serializer to both invocations of json.dumps(). This let's custom objects get correctly returned.
  • Fix the type hinting on OrchestratorState.to_json() since it can set the value of the dictionary to self._output and self._error, both of which are typehinted as being of Any type

I suspect (but haven't verified) that this also fixes a similar bug that prevents the custom_status from being set to a custom json-serializable object

Missing from this PR

Tests. Sorry for not adding them in but I didn't feel like learning the new test framework for this PR. I tested this manually, and if you guys want unit tests for this then I'm hoping it's trivial for you folks to add.

More context

Without this fix, returning a custom JSON-serializable method results in this error:

[2024-03-09T17:44:24.704Z] Executed 'Functions.some_orchestrator' (Failed, Id=605291c9-282c-48eb-986e-d28307099dc6, Duration=228ms)
[2024-03-09T17:44:24.708Z] System.Private.CoreLib: Exception while executing function: Functions.some_orchestrator. System.Private.CoreLib: Orchestrator function 'some_orchestrator' failed: One or more errors occurred. (Result: Failure
Exception: TypeError: Object of type MyCustomObjectis not JSON serializable
Stack:   File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 495, in _handle__invocation_request      
    call_result = await self._loop.run_in_executor(
  File "C:\Python310\lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10\WINDOWS\X64\azure_functions_worker\dispatcher.py", line 768, in _run_sync_func
    return ExtensionManager.get_sync_invocation_wrapper(context,
  File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10\WINDOWS\X64\azure_functions_worker\extension.py", line 215, in _raw_invocation_wrapper
    result = function(**args)
  File "C:\Users\...\fnOrchestrator\.venv\lib\site-packages\azure\durable_functions\orchestrator.py", line 69, in handle
    return Orchestrator(fn).handle(DurableOrchestrationContext.from_json(context_body))
  File "C:\Users\...\fnOrchestrator\.venv\lib\site-packages\azure\durable_functions\orchestrator.py", line 47, in handle
    return self.task_orchestration_executor.execute(context, context.histories, self.fn)
  File "C:\Users\...\fnOrchestrator\.venv\lib\site-packages\azure\durable_functions\models\TaskOrchestrationExecutor.py", line 104, in execute
    return self.get_orchestrator_state_str()
  File "C:\Users\...\fnOrchestrator\.venv\lib\site-packages\azure\durable_functions\models\TaskOrchestrationExecutor.py", line 296, in get_orchestrator_state_str
    return state.to_json_string()
  File "C:\Users\...\fnOrchestrator\.venv\lib\site-packages\azure\durable_functions\models\OrchestratorState.py", line 121, in to_json_string
    return json.dumps(json_dict)
  File "C:\Python310\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\Python310\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Python310\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Python310\lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
).

@ZainRizvi ZainRizvi requested a review from davidmrdavid as a code owner March 9, 2024 18:05
@ZainRizvi ZainRizvi changed the title Support returning json serializable objects from an orchestrator function Bugfix: Support returning json serializable objects from an orchestrator function Mar 9, 2024
Copy link
Member

@cgillum cgillum left a comment

Choose a reason for hiding this comment

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

The change LGTM! I'll wait for @davidmrdavid to take a quick look to confirm before merging.

@davidmrdavid
Copy link
Collaborator

Good catch, thank you for your contribution @ZainRizvi

@davidmrdavid davidmrdavid merged commit e7cb43d into Azure:dev Mar 15, 2024
1 check passed
@ZainRizvi
Copy link
Contributor Author

My pleasure @davidmrdavid. Any idea when this fix might get released?

@davidmrdavid
Copy link
Collaborator

@ZainRizvi - hopefully within the next month or so. We're a bit spread thin at the moment, but there's a few more small changes planned for the SDK that I'd like to include before the next release. I'll track your request to release this asap in my ToDo list though

@mych4nge
Copy link

@davidmrdavid Wouldn't it make sense to make small intermediate bugfix-release containing this fix only?
Or is there any other way to get this change in my app?

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.

4 participants