|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
| 3 | +from dataclasses import dataclass |
3 | 4 | from datetime import timedelta
|
4 | 5 | from typing import (
|
5 | 6 | Any,
|
|
9 | 10 | Union,
|
10 | 11 | )
|
11 | 12 |
|
| 13 | +from nexusrpc.handler import StartOperationContext |
| 14 | + |
12 | 15 | import temporalio.api.common.v1
|
13 | 16 | import temporalio.api.enums.v1
|
14 | 17 | import temporalio.common
|
|
22 | 25 | )
|
23 | 26 |
|
24 | 27 |
|
25 |
| -# Overload for single-param workflow |
26 |
| -# TODO(nexus-prerelease): bring over other overloads |
27 |
| -async def start_workflow( |
28 |
| - workflow: MethodAsyncSingleParam[SelfType, ParamType, ReturnType], |
29 |
| - arg: ParamType, |
30 |
| - *, |
31 |
| - id: str, |
32 |
| - task_queue: Optional[str] = None, |
33 |
| - execution_timeout: Optional[timedelta] = None, |
34 |
| - run_timeout: Optional[timedelta] = None, |
35 |
| - task_timeout: Optional[timedelta] = None, |
36 |
| - id_reuse_policy: temporalio.common.WorkflowIDReusePolicy = temporalio.common.WorkflowIDReusePolicy.ALLOW_DUPLICATE, |
37 |
| - id_conflict_policy: temporalio.common.WorkflowIDConflictPolicy = temporalio.common.WorkflowIDConflictPolicy.UNSPECIFIED, |
38 |
| - retry_policy: Optional[temporalio.common.RetryPolicy] = None, |
39 |
| - cron_schedule: str = "", |
40 |
| - memo: Optional[Mapping[str, Any]] = None, |
41 |
| - search_attributes: Optional[ |
42 |
| - Union[ |
43 |
| - temporalio.common.TypedSearchAttributes, |
44 |
| - temporalio.common.SearchAttributes, |
45 |
| - ] |
46 |
| - ] = None, |
47 |
| - static_summary: Optional[str] = None, |
48 |
| - static_details: Optional[str] = None, |
49 |
| - start_delay: Optional[timedelta] = None, |
50 |
| - start_signal: Optional[str] = None, |
51 |
| - start_signal_args: Sequence[Any] = [], |
52 |
| - rpc_metadata: Mapping[str, str] = {}, |
53 |
| - rpc_timeout: Optional[timedelta] = None, |
54 |
| - request_eager_start: bool = False, |
55 |
| - priority: temporalio.common.Priority = temporalio.common.Priority.default, |
56 |
| - versioning_override: Optional[temporalio.common.VersioningOverride] = None, |
57 |
| -) -> WorkflowHandle[ReturnType]: |
58 |
| - """Start a workflow that will deliver the result of the Nexus operation. |
59 |
| -
|
60 |
| - The workflow will be started in the same namespace as the Nexus worker, using |
61 |
| - the same client as the worker. If task queue is not specified, the worker's task |
62 |
| - queue will be used. |
63 |
| -
|
64 |
| - See :py:meth:`temporalio.client.Client.start_workflow` for all arguments. |
65 |
| -
|
66 |
| - The return value is :py:class:`temporalio.nexus.WorkflowOperationToken`. |
67 |
| - Use :py:meth:`temporalio.nexus.WorkflowOperationToken.to_workflow_handle` |
68 |
| - to get a :py:class:`temporalio.client.WorkflowHandle` for interacting with the |
69 |
| - workflow. |
70 |
| -
|
71 |
| - The workflow will be started as usual, with the following modifications: |
72 |
| -
|
73 |
| - - On workflow completion, Temporal server will deliver the workflow result to |
74 |
| - the Nexus operation caller, using the callback from the Nexus operation start |
75 |
| - request. |
76 |
| -
|
77 |
| - - The request ID from the Nexus operation start request will be used as the |
78 |
| - request ID for the start workflow request. |
79 |
| -
|
80 |
| - - Inbound links to the caller that were submitted in the Nexus start operation |
81 |
| - request will be attached to the started workflow and, outbound links to the |
82 |
| - started workflow will be added to the Nexus start operation response. If the |
83 |
| - Nexus caller is itself a workflow, this means that the workflow in the caller |
84 |
| - namespace web UI will contain links to the started workflow, and vice versa. |
85 |
| - """ |
86 |
| - tctx = _TemporalNexusOperationContext.get() |
87 |
| - start_operation_context = tctx._temporal_start_operation_context |
88 |
| - if not start_operation_context: |
89 |
| - raise RuntimeError( |
90 |
| - "temporalio.nexus.start_workflow() must be called from " |
91 |
| - "within a Nexus start operation context" |
| 28 | +@dataclass |
| 29 | +class WorkflowRunOperationContext: |
| 30 | + start_operation_context: StartOperationContext |
| 31 | + |
| 32 | + # Overload for single-param workflow |
| 33 | + # TODO(nexus-prerelease): bring over other overloads |
| 34 | + async def start_workflow( |
| 35 | + self, |
| 36 | + workflow: MethodAsyncSingleParam[SelfType, ParamType, ReturnType], |
| 37 | + arg: ParamType, |
| 38 | + *, |
| 39 | + id: str, |
| 40 | + task_queue: Optional[str] = None, |
| 41 | + execution_timeout: Optional[timedelta] = None, |
| 42 | + run_timeout: Optional[timedelta] = None, |
| 43 | + task_timeout: Optional[timedelta] = None, |
| 44 | + id_reuse_policy: temporalio.common.WorkflowIDReusePolicy = temporalio.common.WorkflowIDReusePolicy.ALLOW_DUPLICATE, |
| 45 | + id_conflict_policy: temporalio.common.WorkflowIDConflictPolicy = temporalio.common.WorkflowIDConflictPolicy.UNSPECIFIED, |
| 46 | + retry_policy: Optional[temporalio.common.RetryPolicy] = None, |
| 47 | + cron_schedule: str = "", |
| 48 | + memo: Optional[Mapping[str, Any]] = None, |
| 49 | + search_attributes: Optional[ |
| 50 | + Union[ |
| 51 | + temporalio.common.TypedSearchAttributes, |
| 52 | + temporalio.common.SearchAttributes, |
| 53 | + ] |
| 54 | + ] = None, |
| 55 | + static_summary: Optional[str] = None, |
| 56 | + static_details: Optional[str] = None, |
| 57 | + start_delay: Optional[timedelta] = None, |
| 58 | + start_signal: Optional[str] = None, |
| 59 | + start_signal_args: Sequence[Any] = [], |
| 60 | + rpc_metadata: Mapping[str, str] = {}, |
| 61 | + rpc_timeout: Optional[timedelta] = None, |
| 62 | + request_eager_start: bool = False, |
| 63 | + priority: temporalio.common.Priority = temporalio.common.Priority.default, |
| 64 | + versioning_override: Optional[temporalio.common.VersioningOverride] = None, |
| 65 | + ) -> WorkflowHandle[ReturnType]: |
| 66 | + """Start a workflow that will deliver the result of the Nexus operation. |
| 67 | +
|
| 68 | + The workflow will be started in the same namespace as the Nexus worker, using |
| 69 | + the same client as the worker. If task queue is not specified, the worker's task |
| 70 | + queue will be used. |
| 71 | +
|
| 72 | + See :py:meth:`temporalio.client.Client.start_workflow` for all arguments. |
| 73 | +
|
| 74 | + The return value is :py:class:`temporalio.nexus.WorkflowHandle`. |
| 75 | +
|
| 76 | + The workflow will be started as usual, with the following modifications: |
| 77 | +
|
| 78 | + - On workflow completion, Temporal server will deliver the workflow result to |
| 79 | + the Nexus operation caller, using the callback from the Nexus operation start |
| 80 | + request. |
| 81 | +
|
| 82 | + - The request ID from the Nexus operation start request will be used as the |
| 83 | + request ID for the start workflow request. |
| 84 | +
|
| 85 | + - Inbound links to the caller that were submitted in the Nexus start operation |
| 86 | + request will be attached to the started workflow and, outbound links to the |
| 87 | + started workflow will be added to the Nexus start operation response. If the |
| 88 | + Nexus caller is itself a workflow, this means that the workflow in the caller |
| 89 | + namespace web UI will contain links to the started workflow, and vice versa. |
| 90 | + """ |
| 91 | + tctx = _TemporalNexusOperationContext.get() |
| 92 | + start_operation_context = tctx._temporal_start_operation_context |
| 93 | + if not start_operation_context: |
| 94 | + raise RuntimeError( |
| 95 | + "WorkflowRunOperationContext.start_workflow() must be called from " |
| 96 | + "within a Nexus start operation context" |
| 97 | + ) |
| 98 | + |
| 99 | + # TODO(nexus-preview): When sdk-python supports on_conflict_options, Typescript does this: |
| 100 | + # if (workflowOptions.workflowIdConflictPolicy === 'USE_EXISTING') { |
| 101 | + # internalOptions.onConflictOptions = { |
| 102 | + # attachLinks: true, |
| 103 | + # attachCompletionCallbacks: true, |
| 104 | + # attachRequestId: true, |
| 105 | + # }; |
| 106 | + # } |
| 107 | + |
| 108 | + # We must pass nexus_completion_callbacks, workflow_event_links, and request_id, |
| 109 | + # but these are deliberately not exposed in overloads, hence the type-check |
| 110 | + # violation. |
| 111 | + wf_handle = await tctx.client.start_workflow( # type: ignore |
| 112 | + workflow=workflow, |
| 113 | + arg=arg, |
| 114 | + id=id, |
| 115 | + task_queue=task_queue or tctx.info().task_queue, |
| 116 | + execution_timeout=execution_timeout, |
| 117 | + run_timeout=run_timeout, |
| 118 | + task_timeout=task_timeout, |
| 119 | + id_reuse_policy=id_reuse_policy, |
| 120 | + id_conflict_policy=id_conflict_policy, |
| 121 | + retry_policy=retry_policy, |
| 122 | + cron_schedule=cron_schedule, |
| 123 | + memo=memo, |
| 124 | + search_attributes=search_attributes, |
| 125 | + static_summary=static_summary, |
| 126 | + static_details=static_details, |
| 127 | + start_delay=start_delay, |
| 128 | + start_signal=start_signal, |
| 129 | + start_signal_args=start_signal_args, |
| 130 | + rpc_metadata=rpc_metadata, |
| 131 | + rpc_timeout=rpc_timeout, |
| 132 | + request_eager_start=request_eager_start, |
| 133 | + priority=priority, |
| 134 | + versioning_override=versioning_override, |
| 135 | + nexus_completion_callbacks=start_operation_context.get_completion_callbacks(), |
| 136 | + workflow_event_links=start_operation_context.get_workflow_event_links(), |
| 137 | + request_id=start_operation_context.nexus_operation_context.request_id, |
92 | 138 | )
|
93 | 139 |
|
94 |
| - # TODO(nexus-preview): When sdk-python supports on_conflict_options, Typescript does this: |
95 |
| - # if (workflowOptions.workflowIdConflictPolicy === 'USE_EXISTING') { |
96 |
| - # internalOptions.onConflictOptions = { |
97 |
| - # attachLinks: true, |
98 |
| - # attachCompletionCallbacks: true, |
99 |
| - # attachRequestId: true, |
100 |
| - # }; |
101 |
| - # } |
102 |
| - |
103 |
| - # We must pass nexus_completion_callbacks, workflow_event_links, and request_id, |
104 |
| - # but these are deliberately not exposed in overloads, hence the type-check |
105 |
| - # violation. |
106 |
| - wf_handle = await tctx.client.start_workflow( # type: ignore |
107 |
| - workflow=workflow, |
108 |
| - arg=arg, |
109 |
| - id=id, |
110 |
| - task_queue=task_queue or tctx.info().task_queue, |
111 |
| - execution_timeout=execution_timeout, |
112 |
| - run_timeout=run_timeout, |
113 |
| - task_timeout=task_timeout, |
114 |
| - id_reuse_policy=id_reuse_policy, |
115 |
| - id_conflict_policy=id_conflict_policy, |
116 |
| - retry_policy=retry_policy, |
117 |
| - cron_schedule=cron_schedule, |
118 |
| - memo=memo, |
119 |
| - search_attributes=search_attributes, |
120 |
| - static_summary=static_summary, |
121 |
| - static_details=static_details, |
122 |
| - start_delay=start_delay, |
123 |
| - start_signal=start_signal, |
124 |
| - start_signal_args=start_signal_args, |
125 |
| - rpc_metadata=rpc_metadata, |
126 |
| - rpc_timeout=rpc_timeout, |
127 |
| - request_eager_start=request_eager_start, |
128 |
| - priority=priority, |
129 |
| - versioning_override=versioning_override, |
130 |
| - nexus_completion_callbacks=start_operation_context.get_completion_callbacks(), |
131 |
| - workflow_event_links=start_operation_context.get_workflow_event_links(), |
132 |
| - request_id=start_operation_context.nexus_operation_context.request_id, |
133 |
| - ) |
134 |
| - |
135 |
| - start_operation_context.add_outbound_links(wf_handle) |
136 |
| - |
137 |
| - return WorkflowHandle[ReturnType]._unsafe_from_client_workflow_handle(wf_handle) |
| 140 | + start_operation_context.add_outbound_links(wf_handle) |
| 141 | + |
| 142 | + return WorkflowHandle[ReturnType]._unsafe_from_client_workflow_handle(wf_handle) |
0 commit comments