18
18
Optional ,
19
19
Sequence ,
20
20
Type ,
21
+ Union ,
21
22
cast ,
22
23
)
23
24
24
- from typing_extensions import TypedDict
25
+ from typing_extensions import TypeAlias , TypedDict
25
26
26
27
import temporalio .activity
27
28
import temporalio .api .common .v1
48
49
logger = logging .getLogger (__name__ )
49
50
50
51
52
+ @dataclass (frozen = True )
53
+ class PollerBehaviorSimpleMaximum :
54
+ """A poller behavior that will attempt to poll as long as a slot is available, up to the
55
+ provided maximum. Cannot be less than two for workflow tasks, or one for other tasks.
56
+ """
57
+
58
+ maximum : int = 5
59
+
60
+ def _to_bridge (self ) -> temporalio .bridge .worker .PollerBehavior :
61
+ return temporalio .bridge .worker .PollerBehaviorSimpleMaximum (
62
+ simple_maximum = self .maximum
63
+ )
64
+
65
+
66
+ @dataclass (frozen = True )
67
+ class PollerBehaviorAutoscaling :
68
+ """A poller behavior that will automatically scale the number of pollers based on feedback
69
+ from the server. A slot must be available before beginning polling.
70
+ """
71
+
72
+ minimum : int = 1
73
+ """At least this many poll calls will always be attempted (assuming slots are available)."""
74
+ maximum : int = 100
75
+ """At most this many poll calls will ever be open at once. Must be >= `minimum`."""
76
+ initial : int = 5
77
+ """This many polls will be attempted initially before scaling kicks in. Must be between
78
+ `minimum` and `maximum`."""
79
+
80
+ def _to_bridge (self ) -> temporalio .bridge .worker .PollerBehavior :
81
+ return temporalio .bridge .worker .PollerBehaviorAutoscaling (
82
+ minimum = self .minimum ,
83
+ maximum = self .maximum ,
84
+ initial = self .initial ,
85
+ )
86
+
87
+
88
+ PollerBehavior : TypeAlias = Union [
89
+ PollerBehaviorSimpleMaximum ,
90
+ PollerBehaviorAutoscaling ,
91
+ ]
92
+
93
+
51
94
class Worker :
52
95
"""Worker to process workflows and/or activities.
53
96
@@ -76,9 +119,9 @@ def __init__(
76
119
max_concurrent_activities : Optional [int ] = None ,
77
120
max_concurrent_local_activities : Optional [int ] = None ,
78
121
tuner : Optional [WorkerTuner ] = None ,
79
- max_concurrent_workflow_task_polls : int = 5 ,
122
+ max_concurrent_workflow_task_polls : Optional [ int ] = None ,
80
123
nonsticky_to_sticky_poll_ratio : float = 0.2 ,
81
- max_concurrent_activity_task_polls : int = 5 ,
124
+ max_concurrent_activity_task_polls : Optional [ int ] = None ,
82
125
no_remote_activities : bool = False ,
83
126
sticky_queue_schedule_to_start_timeout : timedelta = timedelta (seconds = 10 ),
84
127
max_heartbeat_throttle_interval : timedelta = timedelta (seconds = 60 ),
@@ -94,6 +137,12 @@ def __init__(
94
137
use_worker_versioning : bool = False ,
95
138
disable_safe_workflow_eviction : bool = False ,
96
139
deployment_config : Optional [WorkerDeploymentConfig ] = None ,
140
+ workflow_task_poller_behavior : PollerBehavior = PollerBehaviorSimpleMaximum (
141
+ maximum = 5
142
+ ),
143
+ activity_task_poller_behavior : PollerBehavior = PollerBehaviorSimpleMaximum (
144
+ maximum = 5
145
+ ),
97
146
) -> None :
98
147
"""Create a worker to process workflows and/or activities.
99
148
@@ -152,10 +201,17 @@ def __init__(
152
201
``max_concurrent_workflow_tasks``, ``max_concurrent_activities``, and
153
202
``max_concurrent_local_activities`` arguments.
154
203
204
+ Defaults to fixed-size 100 slots for each slot kind if unset and none of the
205
+ max_* arguments are provided.
206
+
155
207
WARNING: This argument is experimental
156
208
max_concurrent_workflow_task_polls: Maximum number of concurrent
157
209
poll workflow task requests we will perform at a time on this
158
210
worker's task queue.
211
+
212
+ If set, will override any value passed to ``workflow_task_poller_behavior``.
213
+
214
+ WARNING: Deprecated, use ``workflow_task_poller_behavior`` instead
159
215
nonsticky_to_sticky_poll_ratio: max_concurrent_workflow_task_polls *
160
216
this number = the number of max pollers that will be allowed for
161
217
the nonsticky queue when sticky tasks are enabled. If both
@@ -166,6 +222,10 @@ def __init__(
166
222
max_concurrent_activity_task_polls: Maximum number of concurrent
167
223
poll activity task requests we will perform at a time on this
168
224
worker's task queue.
225
+
226
+ If set, will override any value passed to ``activity_task_poller_behavior``.
227
+
228
+ WARNING: Deprecated, use ``activity_task_poller_behavior`` instead
169
229
no_remote_activities: If true, this worker will only handle workflow
170
230
tasks and local activities, it will not poll for activity tasks.
171
231
sticky_queue_schedule_to_start_timeout: How long a workflow task is
@@ -231,6 +291,10 @@ def __init__(
231
291
deployment_config: Deployment config for the worker. Exclusive with `build_id` and
232
292
`use_worker_versioning`.
233
293
WARNING: This is an experimental feature and may change in the future.
294
+ workflow_task_poller_behavior: Specify the behavior of workflow task polling.
295
+ Defaults to a 5-poller maximum.
296
+ activity_task_poller_behavior: Specify the behavior of activity task polling.
297
+ Defaults to a 5-poller maximum.
234
298
"""
235
299
if not activities and not workflows :
236
300
raise ValueError ("At least one activity or workflow must be specified" )
@@ -393,6 +457,15 @@ def __init__(
393
457
build_id = build_id
394
458
)
395
459
460
+ if max_concurrent_workflow_task_polls :
461
+ workflow_task_poller_behavior = PollerBehaviorSimpleMaximum (
462
+ maximum = max_concurrent_workflow_task_polls
463
+ )
464
+ if max_concurrent_activity_task_polls :
465
+ activity_task_poller_behavior = PollerBehaviorSimpleMaximum (
466
+ maximum = max_concurrent_activity_task_polls
467
+ )
468
+
396
469
# Create bridge worker last. We have empirically observed that if it is
397
470
# created before an error is raised from the activity worker
398
471
# constructor, a deadlock/hang will occur presumably while trying to
@@ -408,9 +481,7 @@ def __init__(
408
481
identity_override = identity ,
409
482
max_cached_workflows = max_cached_workflows ,
410
483
tuner = bridge_tuner ,
411
- max_concurrent_workflow_task_polls = max_concurrent_workflow_task_polls ,
412
484
nonsticky_to_sticky_poll_ratio = nonsticky_to_sticky_poll_ratio ,
413
- max_concurrent_activity_task_polls = max_concurrent_activity_task_polls ,
414
485
# We have to disable remote activities if a user asks _or_ if we
415
486
# are not running an activity worker at all. Otherwise shutdown
416
487
# will not proceed properly.
@@ -440,6 +511,8 @@ def __init__(
440
511
else set ()
441
512
),
442
513
versioning_strategy = versioning_strategy ,
514
+ workflow_task_poller_behavior = workflow_task_poller_behavior ._to_bridge (),
515
+ activity_task_poller_behavior = activity_task_poller_behavior ._to_bridge (),
443
516
),
444
517
)
445
518
@@ -696,9 +769,9 @@ class WorkerConfig(TypedDict, total=False):
696
769
max_concurrent_activities : Optional [int ]
697
770
max_concurrent_local_activities : Optional [int ]
698
771
tuner : Optional [WorkerTuner ]
699
- max_concurrent_workflow_task_polls : int
772
+ max_concurrent_workflow_task_polls : Optional [ int ]
700
773
nonsticky_to_sticky_poll_ratio : float
701
- max_concurrent_activity_task_polls : int
774
+ max_concurrent_activity_task_polls : Optional [ int ]
702
775
no_remote_activities : bool
703
776
sticky_queue_schedule_to_start_timeout : timedelta
704
777
max_heartbeat_throttle_interval : timedelta
@@ -714,6 +787,8 @@ class WorkerConfig(TypedDict, total=False):
714
787
use_worker_versioning : bool
715
788
disable_safe_workflow_eviction : bool
716
789
deployment_config : Optional [WorkerDeploymentConfig ]
790
+ workflow_task_poller_behavior : PollerBehavior
791
+ activity_task_poller_behavior : PollerBehavior
717
792
718
793
719
794
@dataclass
0 commit comments