pydocket 0.2.0__py3-none-any.whl → 0.2.1__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.
Potentially problematic release.
This version of pydocket might be problematic. Click here for more details.
- docket/worker.py +43 -4
- {pydocket-0.2.0.dist-info → pydocket-0.2.1.dist-info}/METADATA +1 -1
- {pydocket-0.2.0.dist-info → pydocket-0.2.1.dist-info}/RECORD +6 -6
- {pydocket-0.2.0.dist-info → pydocket-0.2.1.dist-info}/WHEEL +0 -0
- {pydocket-0.2.0.dist-info → pydocket-0.2.1.dist-info}/entry_points.txt +0 -0
- {pydocket-0.2.0.dist-info → pydocket-0.2.1.dist-info}/licenses/LICENSE +0 -0
docket/worker.py
CHANGED
|
@@ -7,6 +7,7 @@ from types import TracebackType
|
|
|
7
7
|
from typing import (
|
|
8
8
|
TYPE_CHECKING,
|
|
9
9
|
Any,
|
|
10
|
+
Callable,
|
|
10
11
|
Mapping,
|
|
11
12
|
Protocol,
|
|
12
13
|
Self,
|
|
@@ -63,6 +64,11 @@ class _stream_due_tasks(Protocol):
|
|
|
63
64
|
class Worker:
|
|
64
65
|
docket: Docket
|
|
65
66
|
name: str
|
|
67
|
+
concurrency: int
|
|
68
|
+
redelivery_timeout: timedelta
|
|
69
|
+
reconnection_delay: timedelta
|
|
70
|
+
minimum_check_interval: timedelta
|
|
71
|
+
_strike_conditions: list[Callable[[Execution], bool]] = []
|
|
66
72
|
|
|
67
73
|
def __init__(
|
|
68
74
|
self,
|
|
@@ -80,6 +86,10 @@ class Worker:
|
|
|
80
86
|
self.reconnection_delay = reconnection_delay
|
|
81
87
|
self.minimum_check_interval = minimum_check_interval
|
|
82
88
|
|
|
89
|
+
self._strike_conditions = [
|
|
90
|
+
docket.strike_list.is_stricken,
|
|
91
|
+
]
|
|
92
|
+
|
|
83
93
|
async def __aenter__(self) -> Self:
|
|
84
94
|
self._heartbeat_task = asyncio.create_task(self._heartbeat())
|
|
85
95
|
|
|
@@ -151,6 +161,35 @@ class Worker:
|
|
|
151
161
|
"""Run the worker indefinitely."""
|
|
152
162
|
return await self._run(forever=True) # pragma: no cover
|
|
153
163
|
|
|
164
|
+
async def run_at_most(self, iterations_by_key: Mapping[str, int]) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Run the worker until there are no more tasks to process, but limit specified
|
|
167
|
+
task keys to a maximum number of iterations.
|
|
168
|
+
|
|
169
|
+
This is particularly useful for testing self-perpetuating tasks that would
|
|
170
|
+
otherwise run indefinitely.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
iterations_by_key: Maps task keys to their maximum allowed executions
|
|
174
|
+
"""
|
|
175
|
+
execution_counts: dict[str, int] = {key: 0 for key in iterations_by_key}
|
|
176
|
+
|
|
177
|
+
def has_reached_max_iterations(execution: Execution) -> bool:
|
|
178
|
+
if execution.key not in iterations_by_key:
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
if execution_counts[execution.key] >= iterations_by_key[execution.key]:
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
execution_counts[execution.key] += 1
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
self._strike_conditions.insert(0, has_reached_max_iterations)
|
|
188
|
+
try:
|
|
189
|
+
await self.run_until_finished()
|
|
190
|
+
finally:
|
|
191
|
+
self._strike_conditions.remove(has_reached_max_iterations)
|
|
192
|
+
|
|
154
193
|
async def _run(self, forever: bool = False) -> None:
|
|
155
194
|
logger.info("Starting worker %r with the following tasks:", self.name)
|
|
156
195
|
for task_name, task in self.docket.tasks.items():
|
|
@@ -322,7 +361,7 @@ class Worker:
|
|
|
322
361
|
await process_completed_tasks()
|
|
323
362
|
|
|
324
363
|
async def _execute(self, message: RedisMessage) -> None:
|
|
325
|
-
log_context:
|
|
364
|
+
log_context: Mapping[str, str | float] = self._log_context()
|
|
326
365
|
|
|
327
366
|
function_name = message[b"function"].decode()
|
|
328
367
|
function = self.docket.tasks.get(function_name)
|
|
@@ -334,13 +373,13 @@ class Worker:
|
|
|
334
373
|
|
|
335
374
|
execution = Execution.from_message(function, message)
|
|
336
375
|
|
|
337
|
-
log_context
|
|
376
|
+
log_context = {**log_context, **execution.specific_labels()}
|
|
338
377
|
counter_labels = {**self.labels(), **execution.general_labels()}
|
|
339
378
|
|
|
340
379
|
arrow = "↬" if execution.attempt > 1 else "↪"
|
|
341
380
|
call = execution.call_repr()
|
|
342
381
|
|
|
343
|
-
if
|
|
382
|
+
if any(condition(execution) for condition in self._strike_conditions):
|
|
344
383
|
arrow = "🗙"
|
|
345
384
|
logger.warning("%s %s", arrow, call, extra=log_context)
|
|
346
385
|
TASKS_STRICKEN.add(1, counter_labels | {"docket.where": "worker"})
|
|
@@ -354,7 +393,7 @@ class Worker:
|
|
|
354
393
|
|
|
355
394
|
start = datetime.now(timezone.utc)
|
|
356
395
|
punctuality = start - execution.when
|
|
357
|
-
log_context
|
|
396
|
+
log_context = {**log_context, "punctuality": punctuality.total_seconds()}
|
|
358
397
|
duration = timedelta(0)
|
|
359
398
|
|
|
360
399
|
TASKS_STARTED.add(1, counter_labels)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydocket
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: A distributed background task system for Python functions
|
|
5
5
|
Project-URL: Homepage, https://github.com/chrisguidry/docket
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/chrisguidry/docket/issues
|
|
@@ -8,9 +8,9 @@ docket/execution.py,sha256=ShP8MoLmxEslk2pAuhKi6KEEKbHdneyQukR9oQwXdjQ,11732
|
|
|
8
8
|
docket/instrumentation.py,sha256=SUVhVFf8AX2HAfmi0HPTT_QvQezlGPJEKs_1YAmrCbA,4454
|
|
9
9
|
docket/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
docket/tasks.py,sha256=RIlSM2omh-YDwVnCz6M5MtmK8T_m_s1w2OlRRxDUs6A,1437
|
|
11
|
-
docket/worker.py,sha256=
|
|
12
|
-
pydocket-0.2.
|
|
13
|
-
pydocket-0.2.
|
|
14
|
-
pydocket-0.2.
|
|
15
|
-
pydocket-0.2.
|
|
16
|
-
pydocket-0.2.
|
|
11
|
+
docket/worker.py,sha256=DH15hW8QBGHaZdOdkpH7bjYtLEydi4sGh-Ei8lEXGOo,20556
|
|
12
|
+
pydocket-0.2.1.dist-info/METADATA,sha256=9DxwXrPzeTCOlxDGn9JUOzQN-k6OjhAJbiRPeMhcNNo,13092
|
|
13
|
+
pydocket-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
pydocket-0.2.1.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
|
|
15
|
+
pydocket-0.2.1.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
|
|
16
|
+
pydocket-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|