pydocket 0.7.0__py3-none-any.whl → 0.7.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/annotations.py +4 -0
- docket/cli.py +26 -0
- docket/dependencies.py +3 -0
- docket/docket.py +43 -0
- docket/execution.py +3 -1
- docket/instrumentation.py +6 -0
- docket/worker.py +8 -3
- {pydocket-0.7.0.dist-info → pydocket-0.7.1.dist-info}/METADATA +1 -1
- pydocket-0.7.1.dist-info/RECORD +16 -0
- pydocket-0.7.0.dist-info/RECORD +0 -16
- {pydocket-0.7.0.dist-info → pydocket-0.7.1.dist-info}/WHEEL +0 -0
- {pydocket-0.7.0.dist-info → pydocket-0.7.1.dist-info}/entry_points.txt +0 -0
- {pydocket-0.7.0.dist-info → pydocket-0.7.1.dist-info}/licenses/LICENSE +0 -0
docket/annotations.py
CHANGED
|
@@ -2,6 +2,8 @@ import abc
|
|
|
2
2
|
import inspect
|
|
3
3
|
from typing import Any, Iterable, Mapping, Self
|
|
4
4
|
|
|
5
|
+
from .instrumentation import CACHE_SIZE
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
class Annotation(abc.ABC):
|
|
7
9
|
_cache: dict[tuple[type[Self], inspect.Signature], Mapping[str, Self]] = {}
|
|
@@ -10,6 +12,7 @@ class Annotation(abc.ABC):
|
|
|
10
12
|
def annotated_parameters(cls, signature: inspect.Signature) -> Mapping[str, Self]:
|
|
11
13
|
key = (cls, signature)
|
|
12
14
|
if key in cls._cache:
|
|
15
|
+
CACHE_SIZE.set(len(cls._cache), {"cache": "annotation"})
|
|
13
16
|
return cls._cache[key]
|
|
14
17
|
|
|
15
18
|
annotated: dict[str, Self] = {}
|
|
@@ -30,6 +33,7 @@ class Annotation(abc.ABC):
|
|
|
30
33
|
annotated[param_name] = arg_type()
|
|
31
34
|
|
|
32
35
|
cls._cache[key] = annotated
|
|
36
|
+
CACHE_SIZE.set(len(cls._cache), {"cache": "annotation"})
|
|
33
37
|
return annotated
|
|
34
38
|
|
|
35
39
|
|
docket/cli.py
CHANGED
|
@@ -358,6 +358,32 @@ def strike(
|
|
|
358
358
|
asyncio.run(run())
|
|
359
359
|
|
|
360
360
|
|
|
361
|
+
@app.command(help="Clear all pending and scheduled tasks from the docket")
|
|
362
|
+
def clear(
|
|
363
|
+
docket_: Annotated[
|
|
364
|
+
str,
|
|
365
|
+
typer.Option(
|
|
366
|
+
"--docket",
|
|
367
|
+
help="The name of the docket",
|
|
368
|
+
envvar="DOCKET_NAME",
|
|
369
|
+
),
|
|
370
|
+
] = "docket",
|
|
371
|
+
url: Annotated[
|
|
372
|
+
str,
|
|
373
|
+
typer.Option(
|
|
374
|
+
help="The URL of the Redis server",
|
|
375
|
+
envvar="DOCKET_URL",
|
|
376
|
+
),
|
|
377
|
+
] = "redis://localhost:6379/0",
|
|
378
|
+
) -> None:
|
|
379
|
+
async def run() -> None:
|
|
380
|
+
async with Docket(name=docket_, url=url) as docket:
|
|
381
|
+
cleared_count = await docket.clear()
|
|
382
|
+
print(f"Cleared {cleared_count} tasks from docket '{docket_}'")
|
|
383
|
+
|
|
384
|
+
asyncio.run(run())
|
|
385
|
+
|
|
386
|
+
|
|
361
387
|
@app.command(help="Restores a task or parameters to the Docket")
|
|
362
388
|
def restore(
|
|
363
389
|
function: Annotated[
|
docket/dependencies.py
CHANGED
|
@@ -21,6 +21,7 @@ from typing import (
|
|
|
21
21
|
|
|
22
22
|
from .docket import Docket
|
|
23
23
|
from .execution import Execution, TaskFunction, get_signature
|
|
24
|
+
from .instrumentation import CACHE_SIZE
|
|
24
25
|
|
|
25
26
|
if TYPE_CHECKING: # pragma: no cover
|
|
26
27
|
from .worker import Worker
|
|
@@ -415,6 +416,7 @@ def get_dependency_parameters(
|
|
|
415
416
|
function: TaskFunction | DependencyFunction[Any],
|
|
416
417
|
) -> dict[str, Dependency]:
|
|
417
418
|
if function in _parameter_cache:
|
|
419
|
+
CACHE_SIZE.set(len(_parameter_cache), {"cache": "parameter"})
|
|
418
420
|
return _parameter_cache[function]
|
|
419
421
|
|
|
420
422
|
dependencies: dict[str, Dependency] = {}
|
|
@@ -428,6 +430,7 @@ def get_dependency_parameters(
|
|
|
428
430
|
dependencies[parameter] = param.default
|
|
429
431
|
|
|
430
432
|
_parameter_cache[function] = dependencies
|
|
433
|
+
CACHE_SIZE.set(len(_parameter_cache), {"cache": "parameter"})
|
|
431
434
|
return dependencies
|
|
432
435
|
|
|
433
436
|
|
docket/docket.py
CHANGED
|
@@ -743,3 +743,46 @@ class Docket:
|
|
|
743
743
|
workers.append(WorkerInfo(worker_name, last_seen, task_names))
|
|
744
744
|
|
|
745
745
|
return workers
|
|
746
|
+
|
|
747
|
+
async def clear(self) -> int:
|
|
748
|
+
"""Clear all pending and scheduled tasks from the docket.
|
|
749
|
+
|
|
750
|
+
This removes all tasks from the stream (immediate tasks) and queue
|
|
751
|
+
(scheduled tasks), along with their associated parked data. Running
|
|
752
|
+
tasks are not affected.
|
|
753
|
+
|
|
754
|
+
Returns:
|
|
755
|
+
The total number of tasks that were cleared.
|
|
756
|
+
"""
|
|
757
|
+
with tracer.start_as_current_span(
|
|
758
|
+
"docket.clear",
|
|
759
|
+
attributes=self.labels(),
|
|
760
|
+
):
|
|
761
|
+
async with self.redis() as redis:
|
|
762
|
+
async with redis.pipeline() as pipeline:
|
|
763
|
+
# Get counts before clearing
|
|
764
|
+
pipeline.xlen(self.stream_key)
|
|
765
|
+
pipeline.zcard(self.queue_key)
|
|
766
|
+
pipeline.zrange(self.queue_key, 0, -1)
|
|
767
|
+
|
|
768
|
+
stream_count: int
|
|
769
|
+
queue_count: int
|
|
770
|
+
scheduled_keys: list[bytes]
|
|
771
|
+
stream_count, queue_count, scheduled_keys = await pipeline.execute()
|
|
772
|
+
|
|
773
|
+
# Clear all data
|
|
774
|
+
# Trim stream to 0 messages instead of deleting it to preserve consumer group
|
|
775
|
+
if stream_count > 0:
|
|
776
|
+
pipeline.xtrim(self.stream_key, maxlen=0, approximate=False)
|
|
777
|
+
pipeline.delete(self.queue_key)
|
|
778
|
+
|
|
779
|
+
# Clear parked task data and known task keys
|
|
780
|
+
for key_bytes in scheduled_keys:
|
|
781
|
+
key = key_bytes.decode()
|
|
782
|
+
pipeline.delete(self.parked_task_key(key))
|
|
783
|
+
pipeline.delete(self.known_task_key(key))
|
|
784
|
+
|
|
785
|
+
await pipeline.execute()
|
|
786
|
+
|
|
787
|
+
total_cleared = stream_count + queue_count
|
|
788
|
+
return total_cleared
|
docket/execution.py
CHANGED
|
@@ -19,7 +19,7 @@ import opentelemetry.context
|
|
|
19
19
|
from opentelemetry import propagate, trace
|
|
20
20
|
|
|
21
21
|
from .annotations import Logged
|
|
22
|
-
from .instrumentation import message_getter
|
|
22
|
+
from .instrumentation import CACHE_SIZE, message_getter
|
|
23
23
|
|
|
24
24
|
logger: logging.Logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
@@ -32,10 +32,12 @@ _signature_cache: dict[Callable[..., Any], inspect.Signature] = {}
|
|
|
32
32
|
|
|
33
33
|
def get_signature(function: Callable[..., Any]) -> inspect.Signature:
|
|
34
34
|
if function in _signature_cache:
|
|
35
|
+
CACHE_SIZE.set(len(_signature_cache), {"cache": "signature"})
|
|
35
36
|
return _signature_cache[function]
|
|
36
37
|
|
|
37
38
|
signature = inspect.signature(function)
|
|
38
39
|
_signature_cache[function] = signature
|
|
40
|
+
CACHE_SIZE.set(len(_signature_cache), {"cache": "signature"})
|
|
39
41
|
return signature
|
|
40
42
|
|
|
41
43
|
|
docket/instrumentation.py
CHANGED
docket/worker.py
CHANGED
|
@@ -15,7 +15,7 @@ from typing import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
from opentelemetry import trace
|
|
18
|
-
from opentelemetry.trace import Tracer
|
|
18
|
+
from opentelemetry.trace import Status, StatusCode, Tracer
|
|
19
19
|
from redis.asyncio import Redis
|
|
20
20
|
from redis.exceptions import ConnectionError, LockError
|
|
21
21
|
|
|
@@ -531,7 +531,7 @@ class Worker:
|
|
|
531
531
|
"code.function.name": execution.function.__name__,
|
|
532
532
|
},
|
|
533
533
|
links=execution.incoming_span_links(),
|
|
534
|
-
):
|
|
534
|
+
) as span:
|
|
535
535
|
try:
|
|
536
536
|
async with resolved_dependencies(self, execution) as dependencies:
|
|
537
537
|
# Preemptively reschedule the perpetual task for the future, or clear
|
|
@@ -576,6 +576,8 @@ class Worker:
|
|
|
576
576
|
duration = log_context["duration"] = time.time() - start
|
|
577
577
|
TASKS_SUCCEEDED.add(1, counter_labels)
|
|
578
578
|
|
|
579
|
+
span.set_status(Status(StatusCode.OK))
|
|
580
|
+
|
|
579
581
|
rescheduled = await self._perpetuate_if_requested(
|
|
580
582
|
execution, dependencies, timedelta(seconds=duration)
|
|
581
583
|
)
|
|
@@ -584,10 +586,13 @@ class Worker:
|
|
|
584
586
|
logger.info(
|
|
585
587
|
"%s [%s] %s", arrow, ms(duration), call, extra=log_context
|
|
586
588
|
)
|
|
587
|
-
except Exception:
|
|
589
|
+
except Exception as e:
|
|
588
590
|
duration = log_context["duration"] = time.time() - start
|
|
589
591
|
TASKS_FAILED.add(1, counter_labels)
|
|
590
592
|
|
|
593
|
+
span.record_exception(e)
|
|
594
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
595
|
+
|
|
591
596
|
retried = await self._retry_if_requested(execution, dependencies)
|
|
592
597
|
if not retried:
|
|
593
598
|
retried = await self._perpetuate_if_requested(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydocket
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.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
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
docket/__init__.py,sha256=sY1T_NVsXQNOmOhOnfYmZ95dcE_52Ov6DSIVIMZp-1w,869
|
|
2
|
+
docket/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
3
|
+
docket/annotations.py,sha256=wttix9UOeMFMAWXAIJUfUw5GjESJZsACb4YXJCozP7Q,2348
|
|
4
|
+
docket/cli.py,sha256=XG_mbjcqNRO0F0hh6l3AwH9bIZv9xJofZaeaAj9nChc,21608
|
|
5
|
+
docket/dependencies.py,sha256=GBwyEY198JFrfm7z5GkLbd84hv7sJktKBMJXv4veWig,17007
|
|
6
|
+
docket/docket.py,sha256=Cw7QB1d0eDwSgwn0Rj26WjFsXSe7MJtfsUBBHGalL7A,26262
|
|
7
|
+
docket/execution.py,sha256=r_2RGC1qhtAcBUg7E6wewLEgftrf3hIxNbH0HnYPbek,14961
|
|
8
|
+
docket/instrumentation.py,sha256=ogvzrfKbWsdPGfdg4hByH3_r5d3b5AwwQkSrmXw0hRg,5492
|
|
9
|
+
docket/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
docket/tasks.py,sha256=RIlSM2omh-YDwVnCz6M5MtmK8T_m_s1w2OlRRxDUs6A,1437
|
|
11
|
+
docket/worker.py,sha256=CY5Z9p8FZw-6WUwp7Ws4A0V7IFTmonSnBmYP-Cp8Fdw,28079
|
|
12
|
+
pydocket-0.7.1.dist-info/METADATA,sha256=00KHm5Er2R6dmjHLTYBUF13kKAeCRPHmDTdAcv5oRcQ,5335
|
|
13
|
+
pydocket-0.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
pydocket-0.7.1.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
|
|
15
|
+
pydocket-0.7.1.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
|
|
16
|
+
pydocket-0.7.1.dist-info/RECORD,,
|
pydocket-0.7.0.dist-info/RECORD
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
docket/__init__.py,sha256=sY1T_NVsXQNOmOhOnfYmZ95dcE_52Ov6DSIVIMZp-1w,869
|
|
2
|
-
docket/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
|
|
3
|
-
docket/annotations.py,sha256=SFBrOMbpAh7P67u8fRTH-u3MVvJQxe0qYi92WAShAsw,2173
|
|
4
|
-
docket/cli.py,sha256=WPm_URZ54h8gHjrsHKP8SXpRzdeepmyH_FhQHai-Qus,20899
|
|
5
|
-
docket/dependencies.py,sha256=fX4vafGjQf7s4x0YROaw7fzQPlYW7TZtCqNhu7Kxj40,16831
|
|
6
|
-
docket/docket.py,sha256=5e101CGLZ2tWNcADo4cdewapmXab47ieMCeQr6d92YQ,24478
|
|
7
|
-
docket/execution.py,sha256=6KozjnS96byvyCMTQ2-IkcIrPsqaPIVu2HZU0U4Be9E,14813
|
|
8
|
-
docket/instrumentation.py,sha256=f-GG5VS6EdS2It30qxjVpzWUBOZQcTnat-3KzPwwDgQ,5367
|
|
9
|
-
docket/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
docket/tasks.py,sha256=RIlSM2omh-YDwVnCz6M5MtmK8T_m_s1w2OlRRxDUs6A,1437
|
|
11
|
-
docket/worker.py,sha256=tJfk2rlHODzHaWBzpBXT8h-Lo7RDQ6gb6HU8b3T9gFA,27878
|
|
12
|
-
pydocket-0.7.0.dist-info/METADATA,sha256=soXf7ybhgvSykxRDH56pMJX2DaXf3SJfDFUFLbebAvM,5335
|
|
13
|
-
pydocket-0.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
-
pydocket-0.7.0.dist-info/entry_points.txt,sha256=4WOk1nUlBsUT5O3RyMci2ImuC5XFswuopElYcLHtD5k,47
|
|
15
|
-
pydocket-0.7.0.dist-info/licenses/LICENSE,sha256=YuVWU_ZXO0K_k2FG8xWKe5RGxV24AhJKTvQmKfqXuyk,1087
|
|
16
|
-
pydocket-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|