pydocket 0.3.0__py3-none-any.whl → 0.3.2__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/execution.py +16 -1
- docket/worker.py +20 -14
- {pydocket-0.3.0.dist-info → pydocket-0.3.2.dist-info}/METADATA +1 -1
- {pydocket-0.3.0.dist-info → pydocket-0.3.2.dist-info}/RECORD +7 -7
- {pydocket-0.3.0.dist-info → pydocket-0.3.2.dist-info}/WHEEL +0 -0
- {pydocket-0.3.0.dist-info → pydocket-0.3.2.dist-info}/entry_points.txt +0 -0
- {pydocket-0.3.0.dist-info → pydocket-0.3.2.dist-info}/licenses/LICENSE +0 -0
docket/execution.py
CHANGED
|
@@ -183,18 +183,33 @@ TaskStrikes = dict[str, ParameterStrikes]
|
|
|
183
183
|
class StrikeList:
|
|
184
184
|
task_strikes: TaskStrikes
|
|
185
185
|
parameter_strikes: ParameterStrikes
|
|
186
|
+
_conditions: list[Callable[[Execution], bool]]
|
|
186
187
|
|
|
187
188
|
def __init__(self) -> None:
|
|
188
189
|
self.task_strikes = {}
|
|
189
190
|
self.parameter_strikes = {}
|
|
191
|
+
self._conditions = [self._matches_task_or_parameter_strike]
|
|
192
|
+
|
|
193
|
+
def add_condition(self, condition: Callable[[Execution], bool]) -> None:
|
|
194
|
+
"""Adds a temporary condition that indicates an execution is stricken."""
|
|
195
|
+
self._conditions.insert(0, condition)
|
|
196
|
+
|
|
197
|
+
def remove_condition(self, condition: Callable[[Execution], bool]) -> None:
|
|
198
|
+
"""Adds a temporary condition that indicates an execution is stricken."""
|
|
199
|
+
assert condition is not self._matches_task_or_parameter_strike
|
|
200
|
+
self._conditions.remove(condition)
|
|
190
201
|
|
|
191
202
|
def is_stricken(self, execution: Execution) -> bool:
|
|
192
203
|
"""
|
|
193
|
-
Checks if an execution is stricken based on task
|
|
204
|
+
Checks if an execution is stricken based on task, parameter, or temporary
|
|
205
|
+
conditions.
|
|
194
206
|
|
|
195
207
|
Returns:
|
|
196
208
|
bool: True if the execution is stricken, False otherwise.
|
|
197
209
|
"""
|
|
210
|
+
return any(condition(execution) for condition in self._conditions)
|
|
211
|
+
|
|
212
|
+
def _matches_task_or_parameter_strike(self, execution: Execution) -> bool:
|
|
198
213
|
function_name = execution.function.__name__
|
|
199
214
|
|
|
200
215
|
# Check if the entire task is stricken (without parameter conditions)
|
docket/worker.py
CHANGED
|
@@ -7,7 +7,6 @@ from types import TracebackType
|
|
|
7
7
|
from typing import (
|
|
8
8
|
TYPE_CHECKING,
|
|
9
9
|
Any,
|
|
10
|
-
Callable,
|
|
11
10
|
Mapping,
|
|
12
11
|
Protocol,
|
|
13
12
|
Self,
|
|
@@ -69,7 +68,6 @@ class Worker:
|
|
|
69
68
|
redelivery_timeout: timedelta
|
|
70
69
|
reconnection_delay: timedelta
|
|
71
70
|
minimum_check_interval: timedelta
|
|
72
|
-
_strike_conditions: list[Callable[[Execution], bool]] = []
|
|
73
71
|
|
|
74
72
|
def __init__(
|
|
75
73
|
self,
|
|
@@ -87,13 +85,9 @@ class Worker:
|
|
|
87
85
|
self.reconnection_delay = reconnection_delay
|
|
88
86
|
self.minimum_check_interval = minimum_check_interval
|
|
89
87
|
|
|
90
|
-
self._strike_conditions = [
|
|
91
|
-
docket.strike_list.is_stricken,
|
|
92
|
-
]
|
|
93
|
-
|
|
94
88
|
async def __aenter__(self) -> Self:
|
|
95
89
|
self._heartbeat_task = asyncio.create_task(self._heartbeat())
|
|
96
|
-
|
|
90
|
+
self._execution_counts = {}
|
|
97
91
|
return self
|
|
98
92
|
|
|
99
93
|
async def __aexit__(
|
|
@@ -102,6 +96,8 @@ class Worker:
|
|
|
102
96
|
exc_value: BaseException | None,
|
|
103
97
|
traceback: TracebackType | None,
|
|
104
98
|
) -> None:
|
|
99
|
+
del self._execution_counts
|
|
100
|
+
|
|
105
101
|
self._heartbeat_task.cancel()
|
|
106
102
|
try:
|
|
107
103
|
await self._heartbeat_task
|
|
@@ -162,6 +158,8 @@ class Worker:
|
|
|
162
158
|
"""Run the worker indefinitely."""
|
|
163
159
|
return await self._run(forever=True) # pragma: no cover
|
|
164
160
|
|
|
161
|
+
_execution_counts: dict[str, int]
|
|
162
|
+
|
|
165
163
|
async def run_at_most(self, iterations_by_key: Mapping[str, int]) -> None:
|
|
166
164
|
"""
|
|
167
165
|
Run the worker until there are no more tasks to process, but limit specified
|
|
@@ -173,23 +171,25 @@ class Worker:
|
|
|
173
171
|
Args:
|
|
174
172
|
iterations_by_key: Maps task keys to their maximum allowed executions
|
|
175
173
|
"""
|
|
176
|
-
|
|
174
|
+
self._execution_counts = {key: 0 for key in iterations_by_key}
|
|
177
175
|
|
|
178
176
|
def has_reached_max_iterations(execution: Execution) -> bool:
|
|
179
|
-
|
|
177
|
+
key = execution.key
|
|
178
|
+
|
|
179
|
+
if key not in iterations_by_key:
|
|
180
180
|
return False
|
|
181
181
|
|
|
182
|
-
if
|
|
182
|
+
if self._execution_counts[key] >= iterations_by_key[key]:
|
|
183
183
|
return True
|
|
184
184
|
|
|
185
|
-
execution_counts[execution.key] += 1
|
|
186
185
|
return False
|
|
187
186
|
|
|
188
|
-
self.
|
|
187
|
+
self.docket.strike_list.add_condition(has_reached_max_iterations)
|
|
189
188
|
try:
|
|
190
189
|
await self.run_until_finished()
|
|
191
190
|
finally:
|
|
192
|
-
self.
|
|
191
|
+
self.docket.strike_list.remove_condition(has_reached_max_iterations)
|
|
192
|
+
self._execution_counts = {}
|
|
193
193
|
|
|
194
194
|
async def _run(self, forever: bool = False) -> None:
|
|
195
195
|
logger.info("Starting worker %r with the following tasks:", self.name)
|
|
@@ -291,6 +291,9 @@ class Worker:
|
|
|
291
291
|
def start_task(
|
|
292
292
|
message_id: RedisMessageID, message: RedisMessage
|
|
293
293
|
) -> None:
|
|
294
|
+
if not message: # pragma: no cover
|
|
295
|
+
return
|
|
296
|
+
|
|
294
297
|
task = asyncio.create_task(self._execute(message))
|
|
295
298
|
active_tasks[task] = message_id
|
|
296
299
|
|
|
@@ -380,12 +383,15 @@ class Worker:
|
|
|
380
383
|
arrow = "↬" if execution.attempt > 1 else "↪"
|
|
381
384
|
call = execution.call_repr()
|
|
382
385
|
|
|
383
|
-
if
|
|
386
|
+
if self.docket.strike_list.is_stricken(execution):
|
|
384
387
|
arrow = "🗙"
|
|
385
388
|
logger.warning("%s %s", arrow, call, extra=log_context)
|
|
386
389
|
TASKS_STRICKEN.add(1, counter_labels | {"docket.where": "worker"})
|
|
387
390
|
return
|
|
388
391
|
|
|
392
|
+
if execution.key in self._execution_counts:
|
|
393
|
+
self._execution_counts[execution.key] += 1
|
|
394
|
+
|
|
389
395
|
dependencies = self._get_dependencies(execution)
|
|
390
396
|
|
|
391
397
|
context = propagate.extract(message, getter=message_getter)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydocket
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
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
|
|
@@ -4,13 +4,13 @@ docket/annotations.py,sha256=GZwOPtPXyeIhnsLh3TQMBnXrjtTtSmF4Ratv4vjPx8U,950
|
|
|
4
4
|
docket/cli.py,sha256=EseF0Sj7IEgd9QDC-FSbHSffvF7DNsrmDGYGgZBdJc8,19413
|
|
5
5
|
docket/dependencies.py,sha256=S3KqXxEF0Q2t_jO3R-kI5IIA3M-tqybtiSod2xnRO4o,4991
|
|
6
6
|
docket/docket.py,sha256=zva6ofTm7i5hRwAaAnNtlgIqoMPaNLqCTs2PXGka_8s,19723
|
|
7
|
-
docket/execution.py,sha256=
|
|
7
|
+
docket/execution.py,sha256=PDrlAr8VzmB6JvqKO71YhXUcTcGQW7eyXrSKiTcAexE,12508
|
|
8
8
|
docket/instrumentation.py,sha256=bZlGA02JoJcY0J1WGm5_qXDfY0AXKr0ZLAYu67wkeKY,4611
|
|
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.3.
|
|
13
|
-
pydocket-0.3.
|
|
14
|
-
pydocket-0.3.
|
|
15
|
-
pydocket-0.3.
|
|
16
|
-
pydocket-0.3.
|
|
11
|
+
docket/worker.py,sha256=MO-j5NQWvhlZh0vCVeUCwLas3i6AVsY672MYgyoU620,21882
|
|
12
|
+
pydocket-0.3.2.dist-info/METADATA,sha256=F0cKpadZ6gQ-mJYXde7XTogoy_uaaTpprpJ5uum9z-w,13092
|
|
13
|
+
pydocket-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
pydocket-0.3.2.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
|
|
15
|
+
pydocket-0.3.2.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
|
|
16
|
+
pydocket-0.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|