cadence-python-client 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. cadence/__init__.py +18 -0
  2. cadence/_internal/__init__.py +8 -0
  3. cadence/_internal/activity/__init__.py +5 -0
  4. cadence/_internal/activity/_activity_executor.py +113 -0
  5. cadence/_internal/activity/_context.py +58 -0
  6. cadence/_internal/rpc/__init__.py +0 -0
  7. cadence/_internal/rpc/error.py +148 -0
  8. cadence/_internal/rpc/retry.py +104 -0
  9. cadence/_internal/rpc/yarpc.py +42 -0
  10. cadence/_internal/workflow/__init__.py +0 -0
  11. cadence/_internal/workflow/context.py +121 -0
  12. cadence/_internal/workflow/decision_events_iterator.py +161 -0
  13. cadence/_internal/workflow/decisions_helper.py +312 -0
  14. cadence/_internal/workflow/deterministic_event_loop.py +498 -0
  15. cadence/_internal/workflow/history_event_iterator.py +58 -0
  16. cadence/_internal/workflow/statemachine/__init__.py +0 -0
  17. cadence/_internal/workflow/statemachine/activity_state_machine.py +106 -0
  18. cadence/_internal/workflow/statemachine/decision_manager.py +157 -0
  19. cadence/_internal/workflow/statemachine/decision_state_machine.py +87 -0
  20. cadence/_internal/workflow/statemachine/event_dispatcher.py +76 -0
  21. cadence/_internal/workflow/statemachine/timer_state_machine.py +73 -0
  22. cadence/_internal/workflow/workflow_engine.py +245 -0
  23. cadence/_internal/workflow/workflow_intance.py +44 -0
  24. cadence/activity.py +255 -0
  25. cadence/api/v1/__init__.py +92 -0
  26. cadence/api/v1/common_pb2.py +90 -0
  27. cadence/api/v1/common_pb2.pyi +200 -0
  28. cadence/api/v1/common_pb2_grpc.py +24 -0
  29. cadence/api/v1/decision_pb2.py +67 -0
  30. cadence/api/v1/decision_pb2.pyi +225 -0
  31. cadence/api/v1/decision_pb2_grpc.py +24 -0
  32. cadence/api/v1/domain_pb2.py +68 -0
  33. cadence/api/v1/domain_pb2.pyi +145 -0
  34. cadence/api/v1/domain_pb2_grpc.py +24 -0
  35. cadence/api/v1/error_pb2.py +59 -0
  36. cadence/api/v1/error_pb2.pyi +82 -0
  37. cadence/api/v1/error_pb2_grpc.py +24 -0
  38. cadence/api/v1/history_pb2.py +134 -0
  39. cadence/api/v1/history_pb2.pyi +780 -0
  40. cadence/api/v1/history_pb2_grpc.py +24 -0
  41. cadence/api/v1/query_pb2.py +49 -0
  42. cadence/api/v1/query_pb2.pyi +59 -0
  43. cadence/api/v1/query_pb2_grpc.py +24 -0
  44. cadence/api/v1/service_domain_pb2.py +76 -0
  45. cadence/api/v1/service_domain_pb2.pyi +164 -0
  46. cadence/api/v1/service_domain_pb2_grpc.py +327 -0
  47. cadence/api/v1/service_meta_pb2.py +41 -0
  48. cadence/api/v1/service_meta_pb2.pyi +17 -0
  49. cadence/api/v1/service_meta_pb2_grpc.py +97 -0
  50. cadence/api/v1/service_visibility_pb2.py +71 -0
  51. cadence/api/v1/service_visibility_pb2.pyi +149 -0
  52. cadence/api/v1/service_visibility_pb2_grpc.py +362 -0
  53. cadence/api/v1/service_worker_pb2.py +116 -0
  54. cadence/api/v1/service_worker_pb2.pyi +350 -0
  55. cadence/api/v1/service_worker_pb2_grpc.py +743 -0
  56. cadence/api/v1/service_workflow_pb2.py +126 -0
  57. cadence/api/v1/service_workflow_pb2.pyi +395 -0
  58. cadence/api/v1/service_workflow_pb2_grpc.py +861 -0
  59. cadence/api/v1/tasklist_pb2.py +78 -0
  60. cadence/api/v1/tasklist_pb2.pyi +147 -0
  61. cadence/api/v1/tasklist_pb2_grpc.py +24 -0
  62. cadence/api/v1/visibility_pb2.py +47 -0
  63. cadence/api/v1/visibility_pb2.pyi +53 -0
  64. cadence/api/v1/visibility_pb2_grpc.py +24 -0
  65. cadence/api/v1/workflow_pb2.py +89 -0
  66. cadence/api/v1/workflow_pb2.pyi +365 -0
  67. cadence/api/v1/workflow_pb2_grpc.py +24 -0
  68. cadence/client.py +382 -0
  69. cadence/data_converter.py +78 -0
  70. cadence/error.py +111 -0
  71. cadence/metrics/__init__.py +12 -0
  72. cadence/metrics/constants.py +136 -0
  73. cadence/metrics/metrics.py +56 -0
  74. cadence/metrics/prometheus.py +165 -0
  75. cadence/sample/__init__.py +1 -0
  76. cadence/sample/client_example.py +15 -0
  77. cadence/sample/grpc_usage_example.py +230 -0
  78. cadence/sample/simple_usage_example.py +155 -0
  79. cadence/signal.py +174 -0
  80. cadence/worker/__init__.py +13 -0
  81. cadence/worker/_activity.py +60 -0
  82. cadence/worker/_base_task_handler.py +71 -0
  83. cadence/worker/_decision.py +62 -0
  84. cadence/worker/_decision_task_handler.py +285 -0
  85. cadence/worker/_poller.py +64 -0
  86. cadence/worker/_registry.py +245 -0
  87. cadence/worker/_types.py +26 -0
  88. cadence/worker/_worker.py +56 -0
  89. cadence/workflow.py +271 -0
  90. cadence_python_client-0.1.0.dist-info/METADATA +180 -0
  91. cadence_python_client-0.1.0.dist-info/RECORD +95 -0
  92. cadence_python_client-0.1.0.dist-info/WHEEL +5 -0
  93. cadence_python_client-0.1.0.dist-info/licenses/LICENSE +201 -0
  94. cadence_python_client-0.1.0.dist-info/licenses/NOTICE +19 -0
  95. cadence_python_client-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple usage example for cadence protobuf modules.
4
+ This demonstrates basic usage patterns for the generated protobuf classes.
5
+ """
6
+
7
+ import sys
8
+ import os
9
+
10
+ # Add the project root to the path so we can import cadence modules
11
+ project_root = os.path.dirname(
12
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
13
+ )
14
+ sys.path.insert(0, project_root)
15
+
16
+
17
+ def example_workflow_execution():
18
+ """Example of creating and using WorkflowExecution objects."""
19
+ print("=== Workflow Execution Example ===")
20
+
21
+ from cadence.api.v1 import common, workflow
22
+
23
+ # Create a workflow execution
24
+ wf_exec = common.WorkflowExecution()
25
+ wf_exec.workflow_id = "my-workflow-123"
26
+ wf_exec.run_id = "run-456"
27
+
28
+ print("Created workflow execution:")
29
+ print(f" - Workflow ID: {wf_exec.workflow_id}")
30
+ print(f" - Run ID: {wf_exec.run_id}")
31
+
32
+ # Create workflow execution info
33
+ wf_info = workflow.WorkflowExecutionInfo()
34
+ wf_info.workflow_execution.CopyFrom(wf_exec)
35
+ wf_info.type.name = "MyWorkflowType"
36
+ wf_info.start_time.seconds = 1234567890
37
+ wf_info.close_time.seconds = 1234567990
38
+
39
+ print("Created workflow execution info:")
40
+ print(f" - Type: {wf_info.type.name}")
41
+ print(f" - Start Time: {wf_info.start_time.seconds}")
42
+ print(f" - Close Time: {wf_info.close_time.seconds}")
43
+
44
+ return wf_exec, wf_info
45
+
46
+
47
+ def example_domain_operations():
48
+ """Example of creating and using Domain objects."""
49
+ print("\n=== Domain Operations Example ===")
50
+
51
+ from cadence.api.v1 import domain
52
+
53
+ # Create a domain
54
+ domain_obj = domain.Domain()
55
+ domain_obj.name = "my-domain"
56
+ domain_obj.status = domain.DOMAIN_STATUS_REGISTERED
57
+ domain_obj.description = "My test domain"
58
+
59
+ print("Created domain:")
60
+ print(f" - Name: {domain_obj.name}")
61
+ print(f" - Status: {domain_obj.status}")
62
+ print(f" - Description: {domain_obj.description}")
63
+
64
+ return domain_obj
65
+
66
+
67
+ def example_enum_usage():
68
+ """Example of using enum values."""
69
+ print("\n=== Enum Usage Example ===")
70
+
71
+ from cadence.api.v1 import workflow
72
+
73
+ # Workflow execution close status
74
+ print("Workflow Execution Close Status:")
75
+ print(f" - COMPLETED: {workflow.WORKFLOW_EXECUTION_CLOSE_STATUS_COMPLETED}")
76
+ print(f" - FAILED: {workflow.WORKFLOW_EXECUTION_CLOSE_STATUS_FAILED}")
77
+ print(f" - CANCELED: {workflow.WORKFLOW_EXECUTION_CLOSE_STATUS_CANCELED}")
78
+ print(f" - TERMINATED: {workflow.WORKFLOW_EXECUTION_CLOSE_STATUS_TERMINATED}")
79
+ print(f" - TIMED_OUT: {workflow.WORKFLOW_EXECUTION_CLOSE_STATUS_TIMED_OUT}")
80
+
81
+ # Timeout types
82
+ print("\nTimeout Types:")
83
+ print(f" - START_TO_CLOSE: {workflow.TIMEOUT_TYPE_START_TO_CLOSE}")
84
+ print(f" - SCHEDULE_TO_CLOSE: {workflow.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE}")
85
+ print(f" - SCHEDULE_TO_START: {workflow.TIMEOUT_TYPE_SCHEDULE_TO_START}")
86
+ print(f" - HEARTBEAT: {workflow.TIMEOUT_TYPE_HEARTBEAT}")
87
+
88
+ # Parent close policies
89
+ print("\nParent Close Policies:")
90
+ print(f" - TERMINATE: {workflow.PARENT_CLOSE_POLICY_TERMINATE}")
91
+ print(f" - ABANDON: {workflow.PARENT_CLOSE_POLICY_ABANDON}")
92
+ print(f" - REQUEST_CANCEL: {workflow.PARENT_CLOSE_POLICY_REQUEST_CANCEL}")
93
+
94
+
95
+ def example_serialization():
96
+ """Example of serializing and deserializing protobuf objects."""
97
+ print("\n=== Serialization Example ===")
98
+
99
+ from cadence.api.v1 import common
100
+
101
+ # Create a workflow execution
102
+ wf_exec = common.WorkflowExecution()
103
+ wf_exec.workflow_id = "serialization-test"
104
+ wf_exec.run_id = "run-789"
105
+
106
+ # Serialize to bytes
107
+ serialized = wf_exec.SerializeToString()
108
+ print(f"Serialized size: {len(serialized)} bytes")
109
+
110
+ # Deserialize from bytes
111
+ new_wf_exec = common.WorkflowExecution()
112
+ new_wf_exec.ParseFromString(serialized)
113
+
114
+ print("Deserialized workflow execution:")
115
+ print(f" - Workflow ID: {new_wf_exec.workflow_id}")
116
+ print(f" - Run ID: {new_wf_exec.run_id}")
117
+
118
+ # Verify they're equal
119
+ if (
120
+ wf_exec.workflow_id == new_wf_exec.workflow_id
121
+ and wf_exec.run_id == new_wf_exec.run_id
122
+ ):
123
+ print("✓ Serialization/deserialization successful!")
124
+ else:
125
+ print("✗ Serialization/deserialization failed!")
126
+
127
+
128
+ def main():
129
+ """Main example function."""
130
+ print("🚀 Cadence Protobuf Usage Examples")
131
+ print("=" * 50)
132
+
133
+ try:
134
+ # Run all examples
135
+ example_workflow_execution()
136
+ example_domain_operations()
137
+ example_enum_usage()
138
+ example_serialization()
139
+
140
+ print("\n" + "=" * 50)
141
+ print("✅ All examples completed successfully!")
142
+ print("The protobuf modules are working correctly and ready for use.")
143
+
144
+ except Exception as e:
145
+ print(f"\n❌ Example failed: {e}")
146
+ import traceback
147
+
148
+ traceback.print_exc()
149
+ return 1
150
+
151
+ return 0
152
+
153
+
154
+ if __name__ == "__main__":
155
+ exit(main())
cadence/signal.py ADDED
@@ -0,0 +1,174 @@
1
+ """
2
+ Signal definition for Cadence workflows.
3
+
4
+ This module provides the SignalDefinition class used internally by WorkflowDefinition
5
+ to track signal handler metadata.
6
+ """
7
+
8
+ import inspect
9
+ from dataclasses import dataclass
10
+ from functools import update_wrapper
11
+ from inspect import Parameter, signature
12
+ from typing import (
13
+ Callable,
14
+ Generic,
15
+ ParamSpec,
16
+ Type,
17
+ TypeVar,
18
+ TypedDict,
19
+ get_type_hints,
20
+ Any,
21
+ )
22
+
23
+ P = ParamSpec("P")
24
+ T = TypeVar("T")
25
+
26
+
27
+ @dataclass(frozen=True)
28
+ class SignalParameter:
29
+ """Parameter metadata for a signal handler."""
30
+
31
+ name: str
32
+ type_hint: Type | None
33
+ has_default: bool
34
+ default_value: Any
35
+
36
+
37
+ class SignalDefinitionOptions(TypedDict, total=False):
38
+ """Options for defining a signal."""
39
+
40
+ name: str
41
+
42
+
43
+ class SignalDefinition(Generic[P, T]):
44
+ """
45
+ Definition of a signal handler with metadata.
46
+
47
+ Similar to ActivityDefinition but for signal handlers.
48
+ Provides type safety and metadata for signal handlers.
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ wrapped: Callable[P, T],
54
+ name: str,
55
+ params: list[SignalParameter],
56
+ is_async: bool,
57
+ ):
58
+ self._wrapped = wrapped
59
+ self._name = name
60
+ self._params = params
61
+ self._is_async = is_async
62
+ update_wrapper(self, wrapped)
63
+
64
+ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
65
+ """Call the wrapped signal handler function."""
66
+ return self._wrapped(*args, **kwargs)
67
+
68
+ @property
69
+ def name(self) -> str:
70
+ """Get the signal name."""
71
+ return self._name
72
+
73
+ @property
74
+ def params(self) -> list[SignalParameter]:
75
+ """Get the signal parameters."""
76
+ return self._params
77
+
78
+ @property
79
+ def is_async(self) -> bool:
80
+ """Check if the signal handler is async."""
81
+ return self._is_async
82
+
83
+ @property
84
+ def wrapped(self) -> Callable[P, T]:
85
+ """Get the wrapped signal handler function."""
86
+ return self._wrapped
87
+
88
+ @staticmethod
89
+ def wrap(
90
+ fn: Callable[P, T], opts: SignalDefinitionOptions
91
+ ) -> "SignalDefinition[P, T]":
92
+ """
93
+ Wrap a function as a SignalDefinition.
94
+
95
+ This is an internal method used by WorkflowDefinition to create signal definitions
96
+ from methods decorated with @workflow.signal.
97
+
98
+ Args:
99
+ fn: The signal handler function to wrap
100
+ opts: Options for the signal definition
101
+
102
+ Returns:
103
+ A SignalDefinition instance
104
+
105
+ Raises:
106
+ ValueError: If return type is not None
107
+ """
108
+ name = opts.get("name") or fn.__qualname__
109
+ is_async = inspect.iscoroutinefunction(fn)
110
+ params = _get_signal_signature(fn)
111
+ _validate_signal_return_type(fn)
112
+
113
+ return SignalDefinition[P, T](fn, name, params, is_async)
114
+
115
+
116
+ def _validate_signal_return_type(fn: Callable) -> None:
117
+ """
118
+ Validate that signal handler returns None.
119
+
120
+ Args:
121
+ fn: The signal handler function
122
+
123
+ Raises:
124
+ ValueError: If return type is not None
125
+ """
126
+ try:
127
+ hints = get_type_hints(fn)
128
+ ret_type = hints.get("return", inspect.Signature.empty)
129
+
130
+ if ret_type is not None and ret_type is not inspect.Signature.empty:
131
+ raise ValueError(
132
+ f"Signal handler '{fn.__qualname__}' must return None "
133
+ f"(signals cannot return values), got {ret_type}"
134
+ )
135
+ except NameError:
136
+ pass
137
+
138
+
139
+ def _get_signal_signature(fn: Callable[P, T]) -> list[SignalParameter]:
140
+ """
141
+ Extract parameter information from a signal handler function.
142
+
143
+ Args:
144
+ fn: The signal handler function
145
+
146
+ Returns:
147
+ List of SignalParameter objects
148
+
149
+ Raises:
150
+ ValueError: If parameters are not positional
151
+ """
152
+ sig = signature(fn)
153
+ args = sig.parameters
154
+ hints = get_type_hints(fn)
155
+ params = []
156
+
157
+ for name, param in args.items():
158
+ # Filter out the self parameter for instance methods
159
+ if param.name == "self":
160
+ continue
161
+
162
+ has_default = param.default != Parameter.empty
163
+ default = param.default if has_default else None
164
+
165
+ if param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD):
166
+ type_hint = hints.get(name, None)
167
+ params.append(SignalParameter(name, type_hint, has_default, default))
168
+ else:
169
+ raise ValueError(
170
+ f"Signal handler '{fn.__qualname__}' parameter '{name}' must be positional, "
171
+ f"got {param.kind.name}"
172
+ )
173
+
174
+ return params
@@ -0,0 +1,13 @@
1
+ from ._worker import Worker, WorkerOptions
2
+
3
+ from ._registry import (
4
+ Registry,
5
+ RegisterWorkflowOptions,
6
+ )
7
+
8
+ __all__ = [
9
+ "Worker",
10
+ "WorkerOptions",
11
+ "Registry",
12
+ "RegisterWorkflowOptions",
13
+ ]
@@ -0,0 +1,60 @@
1
+ import asyncio
2
+ from typing import Optional
3
+
4
+ from cadence._internal.activity import ActivityExecutor
5
+ from cadence.api.v1.service_worker_pb2 import (
6
+ PollForActivityTaskResponse,
7
+ PollForActivityTaskRequest,
8
+ )
9
+ from cadence.api.v1.tasklist_pb2 import TaskList, TaskListKind
10
+ from cadence.client import Client
11
+ from cadence.worker._registry import Registry
12
+ from cadence.worker._types import WorkerOptions, _LONG_POLL_TIMEOUT
13
+ from cadence.worker._poller import Poller
14
+
15
+
16
+ class ActivityWorker:
17
+ def __init__(
18
+ self, client: Client, task_list: str, registry: Registry, options: WorkerOptions
19
+ ) -> None:
20
+ self._client = client
21
+ self._task_list = task_list
22
+ self._identity = options["identity"]
23
+ max_concurrent = options["max_concurrent_activity_execution_size"]
24
+ permits = asyncio.Semaphore(max_concurrent)
25
+ self._executor = ActivityExecutor(
26
+ self._client,
27
+ self._task_list,
28
+ options["identity"],
29
+ max_concurrent,
30
+ registry.get_activity,
31
+ )
32
+ self._poller = Poller[PollForActivityTaskResponse](
33
+ options["activity_task_pollers"], permits, self._poll, self._execute
34
+ )
35
+ # TODO: Local dispatch, local activities, actually running activities, etc
36
+
37
+ async def run(self) -> None:
38
+ await self._poller.run()
39
+
40
+ async def _poll(self) -> Optional[PollForActivityTaskResponse]:
41
+ task: PollForActivityTaskResponse = (
42
+ await self._client.worker_stub.PollForActivityTask(
43
+ PollForActivityTaskRequest(
44
+ domain=self._client.domain,
45
+ task_list=TaskList(
46
+ name=self._task_list, kind=TaskListKind.TASK_LIST_KIND_NORMAL
47
+ ),
48
+ identity=self._identity,
49
+ ),
50
+ timeout=_LONG_POLL_TIMEOUT,
51
+ )
52
+ )
53
+
54
+ if task.task_token:
55
+ return task
56
+ else:
57
+ return None
58
+
59
+ async def _execute(self, task: PollForActivityTaskResponse) -> None:
60
+ await self._executor.execute(task)
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from abc import ABC, abstractmethod
3
+ from typing import TypeVar, Generic
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ class BaseTaskHandler(ABC, Generic[T]):
11
+ """
12
+ Base task handler that provides common functionality for processing tasks.
13
+
14
+ This abstract class defines the interface and common behavior for task handlers
15
+ that process different types of tasks (workflow decisions, activities, etc.).
16
+ """
17
+
18
+ def __init__(self, client, task_list: str, identity: str, **options):
19
+ """
20
+ Initialize the base task handler.
21
+
22
+ Args:
23
+ client: The Cadence client instance
24
+ task_list: The task list name
25
+ identity: Worker identity
26
+ **options: Additional options for the handler
27
+ """
28
+ self._client = client
29
+ self.task_list = task_list
30
+ self._identity = identity
31
+ self._options = options
32
+
33
+ async def handle_task(self, task: T) -> None:
34
+ """
35
+ Handle a single task.
36
+
37
+ This method provides the base implementation for task handling that includes:
38
+ - Error handling
39
+ - Cleanup
40
+
41
+ Args:
42
+ task: The task to handle
43
+ """
44
+ try:
45
+ # Handle the task implementation
46
+ await self._handle_task_implementation(task)
47
+
48
+ except Exception as e:
49
+ logger.exception(f"Error handling task: {e}")
50
+ await self.handle_task_failure(task, e)
51
+
52
+ @abstractmethod
53
+ async def _handle_task_implementation(self, task: T) -> None:
54
+ """
55
+ Handle the actual task implementation.
56
+
57
+ Args:
58
+ task: The task to handle
59
+ """
60
+ pass
61
+
62
+ @abstractmethod
63
+ async def handle_task_failure(self, task: T, error: Exception) -> None:
64
+ """
65
+ Handle task processing failure.
66
+
67
+ Args:
68
+ task: The task that failed
69
+ error: The exception that occurred
70
+ """
71
+ pass
@@ -0,0 +1,62 @@
1
+ import asyncio
2
+ from concurrent.futures import ThreadPoolExecutor
3
+ from typing import Optional
4
+
5
+ from cadence.api.v1.service_worker_pb2 import (
6
+ PollForDecisionTaskRequest,
7
+ PollForDecisionTaskResponse,
8
+ )
9
+ from cadence.api.v1.tasklist_pb2 import TaskList, TaskListKind
10
+ from cadence.client import Client
11
+ from cadence.worker._decision_task_handler import DecisionTaskHandler
12
+ from cadence.worker._poller import Poller
13
+ from cadence.worker._registry import Registry
14
+ from cadence.worker._types import _LONG_POLL_TIMEOUT, WorkerOptions
15
+
16
+
17
+ class DecisionWorker:
18
+ def __init__(
19
+ self, client: Client, task_list: str, registry: Registry, options: WorkerOptions
20
+ ) -> None:
21
+ self._client = client
22
+ self._task_list = task_list
23
+ self._registry = registry
24
+ self._identity = options["identity"]
25
+ permits = asyncio.Semaphore(
26
+ options["max_concurrent_decision_task_execution_size"]
27
+ )
28
+ executor = ThreadPoolExecutor(
29
+ max_workers=options["max_concurrent_decision_task_execution_size"]
30
+ )
31
+ self._decision_handler = DecisionTaskHandler(
32
+ client, task_list, registry, executor=executor, **options
33
+ )
34
+ self._poller = Poller[PollForDecisionTaskResponse](
35
+ options["decision_task_pollers"], permits, self._poll, self._execute
36
+ )
37
+ # TODO: Sticky poller, actually running workflows, etc.
38
+
39
+ async def run(self) -> None:
40
+ await self._poller.run()
41
+
42
+ async def _poll(self) -> Optional[PollForDecisionTaskResponse]:
43
+ task: PollForDecisionTaskResponse = (
44
+ await self._client.worker_stub.PollForDecisionTask(
45
+ PollForDecisionTaskRequest(
46
+ domain=self._client.domain,
47
+ task_list=TaskList(
48
+ name=self._task_list, kind=TaskListKind.TASK_LIST_KIND_NORMAL
49
+ ),
50
+ identity=self._identity,
51
+ ),
52
+ timeout=_LONG_POLL_TIMEOUT,
53
+ )
54
+ )
55
+
56
+ if task and task.task_token:
57
+ return task
58
+ else:
59
+ return None
60
+
61
+ async def _execute(self, task: PollForDecisionTaskResponse) -> None:
62
+ await self._decision_handler.handle_task(task)