temporalio / sdk-python

Temporal Python SDK
MIT License
457 stars 68 forks source link

Workflow init decorator #645

Closed dandavison closed 1 week ago

dandavison commented 2 weeks ago

Closes #600 Supersedes #634

This PR makes it possible to define an __init__ method on a workflow class such that the workflow input is passed to __init__ (in exactly the same way as it is passed to the @workflow.run method, i.e. as one unnamed positional argument per workflow input payload).

Users make use of this feature by using a decorator. Here's a simple example:

@workflow.defn
class WorkflowRunSeesWorkflowInitWorkflow:
    @workflow.init
    def __init__(self, arg: str) -> None:
        self.value = arg

    @workflow.run
    async def run(self, arg: str):
        return f"hello, {self.value}"

However, that example does not show the real purpose of this feature, which is to allow update and signal handlers to access the workflow input, even if they happen to execute in the first workflow task (in which case they will start executing before the main workflow method). Previously, this would have required the handlers to use workflow.wait_condition. See the test test_update_in_first_wft_sees_workflow_init added in this PR.

This PR supersedes #634. That PR attempted to introduce this feature without introducing a decorator, i.e., by inspection of the method signature. However, we have decided that that approach could lead to surprising behavior, especially in situations involving workflow class inheritance.