pydocket 0.1.2__py3-none-any.whl → 0.1.4__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/cli.py +9 -0
- docket/docket.py +21 -8
- docket/worker.py +27 -25
- {pydocket-0.1.2.dist-info → pydocket-0.1.4.dist-info}/METADATA +1 -1
- {pydocket-0.1.2.dist-info → pydocket-0.1.4.dist-info}/RECORD +8 -8
- {pydocket-0.1.2.dist-info → pydocket-0.1.4.dist-info}/WHEEL +0 -0
- {pydocket-0.1.2.dist-info → pydocket-0.1.4.dist-info}/entry_points.txt +0 -0
- {pydocket-0.1.2.dist-info → pydocket-0.1.4.dist-info}/licenses/LICENSE +0 -0
docket/cli.py
CHANGED
|
@@ -228,6 +228,14 @@ def worker(
|
|
|
228
228
|
envvar="DOCKET_WORKER_RECONNECTION_DELAY",
|
|
229
229
|
),
|
|
230
230
|
] = timedelta(seconds=5),
|
|
231
|
+
minimum_check_interval: Annotated[
|
|
232
|
+
timedelta,
|
|
233
|
+
typer.Option(
|
|
234
|
+
parser=duration,
|
|
235
|
+
help="The minimum interval to check for tasks",
|
|
236
|
+
envvar="DOCKET_WORKER_MINIMUM_CHECK_INTERVAL",
|
|
237
|
+
),
|
|
238
|
+
] = timedelta(milliseconds=100),
|
|
231
239
|
until_finished: Annotated[
|
|
232
240
|
bool,
|
|
233
241
|
typer.Option(
|
|
@@ -244,6 +252,7 @@ def worker(
|
|
|
244
252
|
concurrency=concurrency,
|
|
245
253
|
redelivery_timeout=redelivery_timeout,
|
|
246
254
|
reconnection_delay=reconnection_delay,
|
|
255
|
+
minimum_check_interval=minimum_check_interval,
|
|
247
256
|
until_finished=until_finished,
|
|
248
257
|
tasks=tasks,
|
|
249
258
|
)
|
docket/docket.py
CHANGED
|
@@ -147,17 +147,17 @@ class Docket:
|
|
|
147
147
|
self._monitor_strikes_task = asyncio.create_task(self._monitor_strikes())
|
|
148
148
|
|
|
149
149
|
# Ensure that the stream and worker group exist
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
try:
|
|
151
|
+
async with self.redis() as r:
|
|
152
152
|
await r.xgroup_create(
|
|
153
153
|
groupname=self.worker_group_name,
|
|
154
154
|
name=self.stream_key,
|
|
155
155
|
id="0-0",
|
|
156
156
|
mkstream=True,
|
|
157
157
|
)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
except redis.exceptions.RedisError as e:
|
|
159
|
+
if "BUSYGROUP" not in repr(e):
|
|
160
|
+
raise
|
|
161
161
|
|
|
162
162
|
return self
|
|
163
163
|
|
|
@@ -178,8 +178,21 @@ class Docket:
|
|
|
178
178
|
|
|
179
179
|
@asynccontextmanager
|
|
180
180
|
async def redis(self) -> AsyncGenerator[Redis, None]:
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
redis: Redis | None = None
|
|
182
|
+
try:
|
|
183
|
+
redis = await Redis.from_url(
|
|
184
|
+
self.url,
|
|
185
|
+
single_connection_client=True,
|
|
186
|
+
)
|
|
187
|
+
await redis.__aenter__()
|
|
188
|
+
try:
|
|
189
|
+
yield redis
|
|
190
|
+
finally:
|
|
191
|
+
await asyncio.shield(redis.__aexit__(None, None, None))
|
|
192
|
+
finally:
|
|
193
|
+
# redis 4.6.0 doesn't automatically disconnect and leaves connections open
|
|
194
|
+
if redis:
|
|
195
|
+
await asyncio.shield(redis.connection_pool.disconnect())
|
|
183
196
|
|
|
184
197
|
def register(self, function: Callable[..., Awaitable[Any]]) -> None:
|
|
185
198
|
from .dependencies import validate_dependencies
|
|
@@ -513,7 +526,7 @@ class Docket:
|
|
|
513
526
|
)
|
|
514
527
|
running.append(RunningExecution(execution, worker_name, started))
|
|
515
528
|
else:
|
|
516
|
-
future.append(execution)
|
|
529
|
+
future.append(execution) # pragma: no cover
|
|
517
530
|
|
|
518
531
|
for message in queued_messages:
|
|
519
532
|
function = self.tasks[message[b"function"].decode()]
|
docket/worker.py
CHANGED
|
@@ -67,7 +67,7 @@ class Worker:
|
|
|
67
67
|
concurrency: int = 10,
|
|
68
68
|
redelivery_timeout: timedelta = timedelta(minutes=5),
|
|
69
69
|
reconnection_delay: timedelta = timedelta(seconds=5),
|
|
70
|
-
minimum_check_interval: timedelta = timedelta(milliseconds=
|
|
70
|
+
minimum_check_interval: timedelta = timedelta(milliseconds=100),
|
|
71
71
|
) -> None:
|
|
72
72
|
self.docket = docket
|
|
73
73
|
self.name = name or f"worker:{uuid4()}"
|
|
@@ -110,6 +110,7 @@ class Worker:
|
|
|
110
110
|
concurrency: int = 10,
|
|
111
111
|
redelivery_timeout: timedelta = timedelta(minutes=5),
|
|
112
112
|
reconnection_delay: timedelta = timedelta(seconds=5),
|
|
113
|
+
minimum_check_interval: timedelta = timedelta(milliseconds=100),
|
|
113
114
|
until_finished: bool = False,
|
|
114
115
|
tasks: list[str] = ["docket.tasks:standard_tasks"],
|
|
115
116
|
) -> None:
|
|
@@ -123,6 +124,7 @@ class Worker:
|
|
|
123
124
|
concurrency=concurrency,
|
|
124
125
|
redelivery_timeout=redelivery_timeout,
|
|
125
126
|
reconnection_delay=reconnection_delay,
|
|
127
|
+
minimum_check_interval=minimum_check_interval,
|
|
126
128
|
) as worker:
|
|
127
129
|
if until_finished:
|
|
128
130
|
await worker.run_until_finished()
|
|
@@ -170,28 +172,31 @@ class Worker:
|
|
|
170
172
|
"""
|
|
171
173
|
local total_work = redis.call('ZCARD', KEYS[1])
|
|
172
174
|
local due_work = 0
|
|
173
|
-
local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1])
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
local
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
local
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
if total_work > 0 then
|
|
177
|
+
local tasks = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1])
|
|
178
|
+
|
|
179
|
+
for i, key in ipairs(tasks) do
|
|
180
|
+
local hash_key = ARGV[2] .. ":" .. key
|
|
181
|
+
local task_data = redis.call('HGETALL', hash_key)
|
|
182
|
+
|
|
183
|
+
if #task_data > 0 then
|
|
184
|
+
local task = {}
|
|
185
|
+
for j = 1, #task_data, 2 do
|
|
186
|
+
task[task_data[j]] = task_data[j+1]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
redis.call('XADD', KEYS[2], '*',
|
|
190
|
+
'key', task['key'],
|
|
191
|
+
'when', task['when'],
|
|
192
|
+
'function', task['function'],
|
|
193
|
+
'args', task['args'],
|
|
194
|
+
'kwargs', task['kwargs'],
|
|
195
|
+
'attempt', task['attempt']
|
|
196
|
+
)
|
|
197
|
+
redis.call('DEL', hash_key)
|
|
198
|
+
due_work = due_work + 1
|
|
183
199
|
end
|
|
184
|
-
|
|
185
|
-
redis.call('XADD', KEYS[2], '*',
|
|
186
|
-
'key', task['key'],
|
|
187
|
-
'when', task['when'],
|
|
188
|
-
'function', task['function'],
|
|
189
|
-
'args', task['args'],
|
|
190
|
-
'kwargs', task['kwargs'],
|
|
191
|
-
'attempt', task['attempt']
|
|
192
|
-
)
|
|
193
|
-
redis.call('DEL', hash_key)
|
|
194
|
-
due_work = due_work + 1
|
|
195
200
|
end
|
|
196
201
|
end
|
|
197
202
|
|
|
@@ -275,8 +280,6 @@ class Worker:
|
|
|
275
280
|
|
|
276
281
|
for message_id, message in redeliveries:
|
|
277
282
|
start_task(message_id, message)
|
|
278
|
-
if available_slots <= 0:
|
|
279
|
-
break
|
|
280
283
|
|
|
281
284
|
if available_slots <= 0:
|
|
282
285
|
continue
|
|
@@ -295,8 +298,7 @@ class Worker:
|
|
|
295
298
|
for _, messages in new_deliveries:
|
|
296
299
|
for message_id, message in messages:
|
|
297
300
|
start_task(message_id, message)
|
|
298
|
-
|
|
299
|
-
break
|
|
301
|
+
|
|
300
302
|
except asyncio.CancelledError:
|
|
301
303
|
if active_tasks: # pragma: no cover
|
|
302
304
|
logger.info(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydocket
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
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
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
docket/__init__.py,sha256=GoJYpyuO6QFeBB8GNaxGGvMMuai55Eaw_8u-o1PM3hk,743
|
|
2
2
|
docket/__main__.py,sha256=Vkuh7aJ-Bl7QVpVbbkUksAd_hn05FiLmWbc-8kbhZQ4,34
|
|
3
3
|
docket/annotations.py,sha256=GZwOPtPXyeIhnsLh3TQMBnXrjtTtSmF4Ratv4vjPx8U,950
|
|
4
|
-
docket/cli.py,sha256=
|
|
4
|
+
docket/cli.py,sha256=N0vp1zO5Wau4nBDMJOU34hYn11HR3PaYY3Ybk1gS8XY,19188
|
|
5
5
|
docket/dependencies.py,sha256=Vht3qKbik-HQ7jsAU5k-eig4_yuru56-ZewjBVVu4yM,4325
|
|
6
|
-
docket/docket.py,sha256=
|
|
6
|
+
docket/docket.py,sha256=TWeZ63NfN6Eq4lFzKoQTJz88ECZsH3-gqYszhQl-bXs,20124
|
|
7
7
|
docket/execution.py,sha256=rHsQ60BbNREzcpUC_RvbGUctdLaprYp1x46sT6jTrdc,11416
|
|
8
8
|
docket/instrumentation.py,sha256=USo8ptCFcwQj_YaUpJvsUHPb0QfQr50i9dF4tYgYde4,2992
|
|
9
9
|
docket/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
docket/tasks.py,sha256=K1f_W1z4m9RVz1GJ1ymWY5ZaRmqHO1SebNBVENlkelU,1471
|
|
11
|
-
docket/worker.py,sha256=
|
|
12
|
-
pydocket-0.1.
|
|
13
|
-
pydocket-0.1.
|
|
14
|
-
pydocket-0.1.
|
|
15
|
-
pydocket-0.1.
|
|
16
|
-
pydocket-0.1.
|
|
11
|
+
docket/worker.py,sha256=8wnWxHj7ctHPxEGSRxPTsHksZ6OWRoG5dKpSkvIZP88,18479
|
|
12
|
+
pydocket-0.1.4.dist-info/METADATA,sha256=y8PTR9Xwh8MeMr7ZhPJzUQGtQUjQXN3QRpYTvxtKfv0,13092
|
|
13
|
+
pydocket-0.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
pydocket-0.1.4.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
|
|
15
|
+
pydocket-0.1.4.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
|
|
16
|
+
pydocket-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|