durable-workflow 0.1.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.
@@ -0,0 +1,75 @@
1
+ from . import activity, sync, workflow
2
+ from .activity import ActivityContext, ActivityInfo
3
+ from .client import (
4
+ Client,
5
+ ScheduleAction,
6
+ ScheduleBackfillResult,
7
+ ScheduleDescription,
8
+ ScheduleHandle,
9
+ ScheduleList,
10
+ ScheduleSpec,
11
+ ScheduleTriggerResult,
12
+ WorkflowExecution,
13
+ WorkflowHandle,
14
+ WorkflowList,
15
+ )
16
+ from .errors import (
17
+ ActivityCancelled,
18
+ ChildWorkflowFailed,
19
+ DurableWorkflowError,
20
+ InvalidArgument,
21
+ NamespaceNotFound,
22
+ NonRetryableError,
23
+ QueryFailed,
24
+ ScheduleAlreadyExists,
25
+ ScheduleNotFound,
26
+ ServerError,
27
+ Unauthorized,
28
+ UpdateRejected,
29
+ WorkflowAlreadyStarted,
30
+ WorkflowCancelled,
31
+ WorkflowFailed,
32
+ WorkflowNotFound,
33
+ WorkflowTerminated,
34
+ )
35
+ from .worker import Worker
36
+ from .workflow import ContinueAsNew, StartChildWorkflow
37
+
38
+ __all__ = [
39
+ "ActivityCancelled",
40
+ "ActivityContext",
41
+ "ActivityInfo",
42
+ "ChildWorkflowFailed",
43
+ "Client",
44
+ "ContinueAsNew",
45
+ "NonRetryableError",
46
+ "ScheduleAction",
47
+ "ScheduleAlreadyExists",
48
+ "ScheduleBackfillResult",
49
+ "ScheduleDescription",
50
+ "ScheduleHandle",
51
+ "ScheduleList",
52
+ "ScheduleNotFound",
53
+ "ScheduleSpec",
54
+ "ScheduleTriggerResult",
55
+ "StartChildWorkflow",
56
+ "Worker",
57
+ "WorkflowExecution",
58
+ "WorkflowHandle",
59
+ "WorkflowList",
60
+ "activity",
61
+ "sync",
62
+ "workflow",
63
+ "DurableWorkflowError",
64
+ "InvalidArgument",
65
+ "NamespaceNotFound",
66
+ "QueryFailed",
67
+ "ServerError",
68
+ "Unauthorized",
69
+ "UpdateRejected",
70
+ "WorkflowAlreadyStarted",
71
+ "WorkflowCancelled",
72
+ "WorkflowFailed",
73
+ "WorkflowNotFound",
74
+ "WorkflowTerminated",
75
+ ]
@@ -0,0 +1,83 @@
1
+ """Activity decorator, registry, and execution context."""
2
+ from __future__ import annotations
3
+
4
+ import contextvars
5
+ from collections.abc import Callable
6
+ from dataclasses import dataclass
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ from .errors import ActivityCancelled
10
+
11
+ if TYPE_CHECKING:
12
+ from .client import Client
13
+
14
+ _REGISTRY: dict[str, Callable[..., Any]] = {}
15
+
16
+ _current_context: contextvars.ContextVar[ActivityContext | None] = contextvars.ContextVar(
17
+ "activity_context", default=None
18
+ )
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class ActivityInfo:
23
+ task_id: str
24
+ activity_type: str
25
+ activity_attempt_id: str
26
+ attempt_number: int
27
+ task_queue: str
28
+ worker_id: str
29
+
30
+
31
+ class ActivityContext:
32
+ def __init__(
33
+ self,
34
+ *,
35
+ info: ActivityInfo,
36
+ client: Client,
37
+ ) -> None:
38
+ self._info = info
39
+ self._client = client
40
+ self._cancel_requested = False
41
+
42
+ @property
43
+ def info(self) -> ActivityInfo:
44
+ return self._info
45
+
46
+ @property
47
+ def is_cancelled(self) -> bool:
48
+ return self._cancel_requested
49
+
50
+ async def heartbeat(self, details: dict[str, Any] | None = None) -> None:
51
+ resp = await self._client.heartbeat_activity_task(
52
+ task_id=self._info.task_id,
53
+ activity_attempt_id=self._info.activity_attempt_id,
54
+ lease_owner=self._info.worker_id,
55
+ details=details,
56
+ )
57
+ if isinstance(resp, dict) and resp.get("cancel_requested"):
58
+ self._cancel_requested = True
59
+ raise ActivityCancelled()
60
+
61
+
62
+ def context() -> ActivityContext:
63
+ ctx = _current_context.get()
64
+ if ctx is None:
65
+ raise RuntimeError("activity.context() called outside of an activity execution")
66
+ return ctx
67
+
68
+
69
+ def _set_context(ctx: ActivityContext | None) -> contextvars.Token[ActivityContext | None]:
70
+ return _current_context.set(ctx)
71
+
72
+
73
+ def defn(*, name: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
74
+ def wrap(fn: Callable[..., Any]) -> Callable[..., Any]:
75
+ fn.__activity_name__ = name # type: ignore[attr-defined]
76
+ _REGISTRY[name] = fn
77
+ return fn
78
+
79
+ return wrap
80
+
81
+
82
+ def registry() -> dict[str, Callable[..., Any]]:
83
+ return dict(_REGISTRY)