pydocket 0.3.1__py3-none-any.whl → 0.4.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.

Potentially problematic release.


This version of pydocket might be problematic. Click here for more details.

docket/docket.py CHANGED
@@ -132,6 +132,9 @@ class Docket:
132
132
  - "redis://user:password@localhost:6379/0?ssl=true"
133
133
  - "rediss://localhost:6379/0"
134
134
  - "unix:///path/to/redis.sock"
135
+ heartbeat_interval: How often workers send heartbeat messages to the docket.
136
+ missed_heartbeats: How many heartbeats a worker can miss before it is
137
+ considered dead.
135
138
  """
136
139
  self.name = name
137
140
  self.url = url
@@ -305,6 +308,9 @@ class Docket:
305
308
  def stream_key(self) -> str:
306
309
  return f"{self.name}:stream"
307
310
 
311
+ def known_task_key(self, key: str) -> str:
312
+ return f"{self.name}:known:{key}"
313
+
308
314
  def parked_task_key(self, key: str) -> str:
309
315
  return f"{self.name}:{key}"
310
316
 
@@ -340,30 +346,36 @@ class Docket:
340
346
  when = execution.when
341
347
 
342
348
  async with self.redis() as redis:
343
- # if the task is already in the queue, retain it
344
- if await redis.zscore(self.queue_key, key) is not None:
349
+ # if the task is already in the queue or stream, retain it
350
+ if await redis.exists(self.known_task_key(key)):
351
+ logger.debug(
352
+ "Task %r is already in the queue or stream, skipping schedule",
353
+ key,
354
+ extra=self.labels(),
355
+ )
345
356
  return
346
357
 
347
- if when <= datetime.now(timezone.utc):
348
- await redis.xadd(self.stream_key, message) # type: ignore[arg-type]
349
- else:
350
- async with redis.pipeline() as pipe:
358
+ async with redis.pipeline() as pipe:
359
+ pipe.set(self.known_task_key(key), when.timestamp())
360
+
361
+ if when <= datetime.now(timezone.utc):
362
+ pipe.xadd(self.stream_key, message) # type: ignore[arg-type]
363
+ else:
351
364
  pipe.hset(self.parked_task_key(key), mapping=message) # type: ignore[arg-type]
352
365
  pipe.zadd(self.queue_key, {key: when.timestamp()})
353
- await pipe.execute()
366
+
367
+ await pipe.execute()
354
368
 
355
369
  TASKS_SCHEDULED.add(1, {**self.labels(), **execution.general_labels()})
356
370
 
357
371
  async def cancel(self, key: str) -> None:
358
372
  with tracer.start_as_current_span(
359
373
  "docket.cancel",
360
- attributes={
361
- **self.labels(),
362
- "docket.key": key,
363
- },
374
+ attributes={**self.labels(), "docket.key": key},
364
375
  ):
365
376
  async with self.redis() as redis:
366
377
  async with redis.pipeline() as pipe:
378
+ pipe.delete(self.known_task_key(key))
367
379
  pipe.delete(self.parked_task_key(key))
368
380
  pipe.zrem(self.queue_key, key)
369
381
  await pipe.execute()
docket/worker.py CHANGED
@@ -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
 
@@ -374,6 +377,9 @@ class Worker:
374
377
 
375
378
  execution = Execution.from_message(function, message)
376
379
 
380
+ async with self.docket.redis() as redis:
381
+ await redis.delete(self.docket.known_task_key(execution.key))
382
+
377
383
  log_context = {**log_context, **execution.specific_labels()}
378
384
  counter_labels = {**self.labels(), **execution.general_labels()}
379
385
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydocket
3
- Version: 0.3.1
3
+ Version: 0.4.0
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
@@ -3,14 +3,14 @@ docket/__main__.py,sha256=Vkuh7aJ-Bl7QVpVbbkUksAd_hn05FiLmWbc-8kbhZQ4,34
3
3
  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
- docket/docket.py,sha256=zva6ofTm7i5hRwAaAnNtlgIqoMPaNLqCTs2PXGka_8s,19723
6
+ docket/docket.py,sha256=xjmXZtE2QY6Pet5Gv5hEJNr8d5wp3zL1GJqRbJYwnKs,20321
7
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=AO5k7rn5xHLGN0L6vckQuMyt_LSHh01me_LqNtsobtc,21786
12
- pydocket-0.3.1.dist-info/METADATA,sha256=tIHiKQjQ-to6bp437vH3-2LsUPnfUP-iG61FAcQa2GE,13092
13
- pydocket-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
- pydocket-0.3.1.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
15
- pydocket-0.3.1.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
16
- pydocket-0.3.1.dist-info/RECORD,,
11
+ docket/worker.py,sha256=3gyXOMaXTBAqEMJqTbItssWtil4ZtVT32UZZoaqWxK0,22006
12
+ pydocket-0.4.0.dist-info/METADATA,sha256=eZAK9MrnZBJhgH8Nc_JDWykcETUU5wszL0KbAPq8ha0,13092
13
+ pydocket-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ pydocket-0.4.0.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
15
+ pydocket-0.4.0.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
16
+ pydocket-0.4.0.dist-info/RECORD,,