hatchet-sdk 1.0.0a1__py3-none-any.whl → 1.0.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 hatchet-sdk might be problematic. Click here for more details.
- hatchet_sdk/__init__.py +5 -0
- hatchet_sdk/client.py +17 -5
- hatchet_sdk/clients/admin.py +0 -18
- hatchet_sdk/clients/rest/models/workflow_runs_metrics.py +5 -1
- hatchet_sdk/clients/v1/api_client.py +81 -0
- hatchet_sdk/context/context.py +1 -12
- hatchet_sdk/features/cron.py +89 -119
- hatchet_sdk/features/logs.py +16 -0
- hatchet_sdk/features/metrics.py +75 -0
- hatchet_sdk/features/rate_limits.py +45 -0
- hatchet_sdk/features/runs.py +221 -0
- hatchet_sdk/features/scheduled.py +114 -131
- hatchet_sdk/features/workers.py +41 -0
- hatchet_sdk/features/workflows.py +55 -0
- hatchet_sdk/hatchet.py +36 -14
- hatchet_sdk/runnables/standalone.py +9 -11
- hatchet_sdk/runnables/types.py +1 -1
- hatchet_sdk/runnables/workflow.py +26 -19
- hatchet_sdk/worker/action_listener_process.py +3 -3
- hatchet_sdk/worker/runner/run_loop_manager.py +0 -1
- hatchet_sdk/worker/runner/runner.py +0 -6
- {hatchet_sdk-1.0.0a1.dist-info → hatchet_sdk-1.0.1.dist-info}/METADATA +1 -1
- {hatchet_sdk-1.0.0a1.dist-info → hatchet_sdk-1.0.1.dist-info}/RECORD +25 -19
- hatchet_sdk/clients/rest_client.py +0 -657
- {hatchet_sdk-1.0.0a1.dist-info → hatchet_sdk-1.0.1.dist-info}/WHEEL +0 -0
- {hatchet_sdk-1.0.0a1.dist-info → hatchet_sdk-1.0.1.dist-info}/entry_points.txt +0 -0
hatchet_sdk/__init__.py
CHANGED
|
@@ -98,6 +98,7 @@ from hatchet_sdk.clients.rest.models.user_tenant_memberships_list import (
|
|
|
98
98
|
UserTenantMembershipsList,
|
|
99
99
|
)
|
|
100
100
|
from hatchet_sdk.clients.rest.models.user_tenant_public import UserTenantPublic
|
|
101
|
+
from hatchet_sdk.clients.rest.models.v1_task_status import V1TaskStatus
|
|
101
102
|
from hatchet_sdk.clients.rest.models.worker_list import WorkerList
|
|
102
103
|
from hatchet_sdk.clients.rest.models.workflow import Workflow
|
|
103
104
|
from hatchet_sdk.clients.rest.models.workflow_deployment_config import (
|
|
@@ -135,6 +136,7 @@ from hatchet_sdk.contracts.workflows_pb2 import (
|
|
|
135
136
|
RateLimitDuration,
|
|
136
137
|
WorkerLabelComparator,
|
|
137
138
|
)
|
|
139
|
+
from hatchet_sdk.features.runs import BulkCancelReplayOpts, RunFilter
|
|
138
140
|
from hatchet_sdk.hatchet import Hatchet
|
|
139
141
|
from hatchet_sdk.runnables.task import Task
|
|
140
142
|
from hatchet_sdk.runnables.types import (
|
|
@@ -264,4 +266,7 @@ __all__ = [
|
|
|
264
266
|
"DurableContext",
|
|
265
267
|
"RegisterDurableEventRequest",
|
|
266
268
|
"TaskDefaults",
|
|
269
|
+
"BulkCancelReplayOpts",
|
|
270
|
+
"RunFilter",
|
|
271
|
+
"V1TaskStatus",
|
|
267
272
|
]
|
hatchet_sdk/client.py
CHANGED
|
@@ -5,11 +5,18 @@ import grpc
|
|
|
5
5
|
from hatchet_sdk.clients.admin import AdminClient
|
|
6
6
|
from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
|
|
7
7
|
from hatchet_sdk.clients.events import EventClient, new_event
|
|
8
|
-
from hatchet_sdk.clients.rest_client import RestApi
|
|
9
8
|
from hatchet_sdk.clients.run_event_listener import RunEventListenerClient
|
|
10
9
|
from hatchet_sdk.clients.workflow_listener import PooledWorkflowRunListener
|
|
11
10
|
from hatchet_sdk.config import ClientConfig
|
|
12
11
|
from hatchet_sdk.connection import new_conn
|
|
12
|
+
from hatchet_sdk.features.cron import CronClient
|
|
13
|
+
from hatchet_sdk.features.logs import LogsClient
|
|
14
|
+
from hatchet_sdk.features.metrics import MetricsClient
|
|
15
|
+
from hatchet_sdk.features.rate_limits import RateLimitsClient
|
|
16
|
+
from hatchet_sdk.features.runs import RunsClient
|
|
17
|
+
from hatchet_sdk.features.scheduled import ScheduledClient
|
|
18
|
+
from hatchet_sdk.features.workers import WorkersClient
|
|
19
|
+
from hatchet_sdk.features.workflows import WorkflowsClient
|
|
13
20
|
|
|
14
21
|
|
|
15
22
|
class Client:
|
|
@@ -20,7 +27,6 @@ class Client:
|
|
|
20
27
|
admin_client: AdminClient | None = None,
|
|
21
28
|
dispatcher_client: DispatcherClient | None = None,
|
|
22
29
|
workflow_listener: PooledWorkflowRunListener | None | None = None,
|
|
23
|
-
rest_client: RestApi | None = None,
|
|
24
30
|
debug: bool = False,
|
|
25
31
|
):
|
|
26
32
|
try:
|
|
@@ -35,10 +41,16 @@ class Client:
|
|
|
35
41
|
self.admin = admin_client or AdminClient(config)
|
|
36
42
|
self.dispatcher = dispatcher_client or DispatcherClient(config)
|
|
37
43
|
self.event = event_client or new_event(conn, config)
|
|
38
|
-
self.rest = rest_client or RestApi(
|
|
39
|
-
config.server_url, config.token, config.tenant_id
|
|
40
|
-
)
|
|
41
44
|
self.listener = RunEventListenerClient(config)
|
|
42
45
|
self.workflow_listener = workflow_listener
|
|
43
46
|
self.logInterceptor = config.logger
|
|
44
47
|
self.debug = debug
|
|
48
|
+
|
|
49
|
+
self.cron = CronClient(self.config)
|
|
50
|
+
self.logs = LogsClient(self.config)
|
|
51
|
+
self.metrics = MetricsClient(self.config)
|
|
52
|
+
self.rate_limits = RateLimitsClient(self.config)
|
|
53
|
+
self.runs = RunsClient(self.config)
|
|
54
|
+
self.scheduled = ScheduledClient(self.config)
|
|
55
|
+
self.workers = WorkersClient(self.config)
|
|
56
|
+
self.workflows = WorkflowsClient(self.config)
|
hatchet_sdk/clients/admin.py
CHANGED
|
@@ -163,12 +163,6 @@ class AdminClient:
|
|
|
163
163
|
workflow: workflow_protos.CreateWorkflowVersionRequest,
|
|
164
164
|
overrides: workflow_protos.CreateWorkflowVersionRequest | None = None,
|
|
165
165
|
) -> workflow_protos.CreateWorkflowVersionResponse:
|
|
166
|
-
## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
|
|
167
|
-
## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
|
|
168
|
-
## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
|
|
169
|
-
if not self.pooled_workflow_listener:
|
|
170
|
-
self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
|
|
171
|
-
|
|
172
166
|
return await asyncio.to_thread(self.put_workflow, name, workflow, overrides)
|
|
173
167
|
|
|
174
168
|
@tenacity_retry
|
|
@@ -178,12 +172,6 @@ class AdminClient:
|
|
|
178
172
|
limit: int,
|
|
179
173
|
duration: RateLimitDuration = RateLimitDuration.SECOND,
|
|
180
174
|
) -> None:
|
|
181
|
-
## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
|
|
182
|
-
## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
|
|
183
|
-
## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
|
|
184
|
-
if not self.pooled_workflow_listener:
|
|
185
|
-
self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
|
|
186
|
-
|
|
187
175
|
return await asyncio.to_thread(self.put_rate_limit, key, limit, duration)
|
|
188
176
|
|
|
189
177
|
@tenacity_retry
|
|
@@ -194,12 +182,6 @@ class AdminClient:
|
|
|
194
182
|
input: JSONSerializableMapping = {},
|
|
195
183
|
options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
|
|
196
184
|
) -> v0_workflow_protos.WorkflowVersion:
|
|
197
|
-
## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
|
|
198
|
-
## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
|
|
199
|
-
## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
|
|
200
|
-
if not self.pooled_workflow_listener:
|
|
201
|
-
self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
|
|
202
|
-
|
|
203
185
|
return await asyncio.to_thread(
|
|
204
186
|
self.schedule_workflow, name, schedules, input, options
|
|
205
187
|
)
|
|
@@ -22,13 +22,17 @@ from typing import Any, ClassVar, Dict, List, Optional, Set
|
|
|
22
22
|
from pydantic import BaseModel, ConfigDict
|
|
23
23
|
from typing_extensions import Self
|
|
24
24
|
|
|
25
|
+
from hatchet_sdk.clients.rest.models.workflow_runs_metrics_counts import (
|
|
26
|
+
WorkflowRunsMetricsCounts,
|
|
27
|
+
)
|
|
28
|
+
|
|
25
29
|
|
|
26
30
|
class WorkflowRunsMetrics(BaseModel):
|
|
27
31
|
"""
|
|
28
32
|
WorkflowRunsMetrics
|
|
29
33
|
""" # noqa: E501
|
|
30
34
|
|
|
31
|
-
counts: Optional[
|
|
35
|
+
counts: Optional[WorkflowRunsMetricsCounts] = None
|
|
32
36
|
__properties: ClassVar[List[str]] = ["counts"]
|
|
33
37
|
|
|
34
38
|
model_config = ConfigDict(
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
3
|
+
from typing import AsyncContextManager, Callable, Coroutine, ParamSpec, TypeVar
|
|
4
|
+
|
|
5
|
+
from hatchet_sdk.clients.rest.api_client import ApiClient
|
|
6
|
+
from hatchet_sdk.clients.rest.configuration import Configuration
|
|
7
|
+
from hatchet_sdk.config import ClientConfig
|
|
8
|
+
from hatchet_sdk.utils.typing import JSONSerializableMapping
|
|
9
|
+
|
|
10
|
+
## Type variables to use with coroutines.
|
|
11
|
+
## See https://stackoverflow.com/questions/73240620/the-right-way-to-type-hint-a-coroutine-function
|
|
12
|
+
## Return type
|
|
13
|
+
R = TypeVar("R")
|
|
14
|
+
|
|
15
|
+
## Yield type
|
|
16
|
+
Y = TypeVar("Y")
|
|
17
|
+
|
|
18
|
+
## Send type
|
|
19
|
+
S = TypeVar("S")
|
|
20
|
+
|
|
21
|
+
P = ParamSpec("P")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def maybe_additional_metadata_to_kv(
|
|
25
|
+
additional_metadata: dict[str, str] | JSONSerializableMapping | None
|
|
26
|
+
) -> list[str] | None:
|
|
27
|
+
if not additional_metadata:
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
return [f"{k}:{v}" for k, v in additional_metadata.items()]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BaseRestClient:
|
|
34
|
+
def __init__(self, config: ClientConfig) -> None:
|
|
35
|
+
self.tenant_id = config.tenant_id
|
|
36
|
+
|
|
37
|
+
self.client_config = config
|
|
38
|
+
self.api_config = Configuration(
|
|
39
|
+
host=config.server_url,
|
|
40
|
+
access_token=config.token,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
self.api_config.datetime_format = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
44
|
+
|
|
45
|
+
def client(self) -> AsyncContextManager[ApiClient]:
|
|
46
|
+
return ApiClient(self.api_config)
|
|
47
|
+
|
|
48
|
+
def _run_async_function_do_not_use_directly(
|
|
49
|
+
self,
|
|
50
|
+
async_func: Callable[P, Coroutine[Y, S, R]],
|
|
51
|
+
*args: P.args,
|
|
52
|
+
**kwargs: P.kwargs,
|
|
53
|
+
) -> R:
|
|
54
|
+
loop = asyncio.new_event_loop()
|
|
55
|
+
asyncio.set_event_loop(loop)
|
|
56
|
+
try:
|
|
57
|
+
return loop.run_until_complete(async_func(*args, **kwargs))
|
|
58
|
+
finally:
|
|
59
|
+
loop.close()
|
|
60
|
+
|
|
61
|
+
def _run_async_from_sync(
|
|
62
|
+
self,
|
|
63
|
+
async_func: Callable[P, Coroutine[Y, S, R]],
|
|
64
|
+
*args: P.args,
|
|
65
|
+
**kwargs: P.kwargs,
|
|
66
|
+
) -> R:
|
|
67
|
+
try:
|
|
68
|
+
loop = asyncio.get_event_loop()
|
|
69
|
+
except RuntimeError:
|
|
70
|
+
loop = None
|
|
71
|
+
|
|
72
|
+
if loop and loop.is_running():
|
|
73
|
+
return loop.run_until_complete(async_func(*args, **kwargs))
|
|
74
|
+
else:
|
|
75
|
+
with ThreadPoolExecutor() as executor:
|
|
76
|
+
future = executor.submit(
|
|
77
|
+
lambda: self._run_async_function_do_not_use_directly(
|
|
78
|
+
async_func, *args, **kwargs
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
return future.result()
|
hatchet_sdk/context/context.py
CHANGED
|
@@ -17,9 +17,6 @@ from hatchet_sdk.clients.durable_event_listener import (
|
|
|
17
17
|
RegisterDurableEventRequest,
|
|
18
18
|
)
|
|
19
19
|
from hatchet_sdk.clients.events import EventClient
|
|
20
|
-
from hatchet_sdk.clients.rest_client import RestApi
|
|
21
|
-
from hatchet_sdk.clients.run_event_listener import RunEventListenerClient
|
|
22
|
-
from hatchet_sdk.clients.workflow_listener import PooledWorkflowRunListener
|
|
23
20
|
from hatchet_sdk.context.worker_context import WorkerContext
|
|
24
21
|
from hatchet_sdk.logger import logger
|
|
25
22
|
from hatchet_sdk.utils.timedelta_to_expression import Duration, timedelta_to_expr
|
|
@@ -53,12 +50,8 @@ class Context:
|
|
|
53
50
|
dispatcher_client: DispatcherClient,
|
|
54
51
|
admin_client: AdminClient,
|
|
55
52
|
event_client: EventClient,
|
|
56
|
-
rest_client: RestApi,
|
|
57
|
-
workflow_listener: PooledWorkflowRunListener | None,
|
|
58
53
|
durable_event_listener: DurableEventListener | None,
|
|
59
|
-
workflow_run_event_listener: RunEventListenerClient,
|
|
60
54
|
worker: WorkerContext,
|
|
61
|
-
namespace: str = "",
|
|
62
55
|
validator_registry: dict[str, WorkflowValidator] = {},
|
|
63
56
|
):
|
|
64
57
|
self.worker = worker
|
|
@@ -68,16 +61,12 @@ class Context:
|
|
|
68
61
|
|
|
69
62
|
self.action = action
|
|
70
63
|
|
|
71
|
-
self.step_run_id
|
|
64
|
+
self.step_run_id = action.step_run_id
|
|
72
65
|
self.exit_flag = False
|
|
73
66
|
self.dispatcher_client = dispatcher_client
|
|
74
67
|
self.admin_client = admin_client
|
|
75
68
|
self.event_client = event_client
|
|
76
|
-
self.rest_client = rest_client
|
|
77
|
-
self.workflow_listener = workflow_listener
|
|
78
69
|
self.durable_event_listener = durable_event_listener
|
|
79
|
-
self.workflow_run_event_listener = workflow_run_event_listener
|
|
80
|
-
self.namespace = namespace
|
|
81
70
|
|
|
82
71
|
# FIXME: this limits the number of concurrent log requests to 1, which means we can do about
|
|
83
72
|
# 100 log lines per second but this depends on network.
|
hatchet_sdk/features/cron.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
from typing import List, Union
|
|
2
|
-
|
|
3
1
|
from pydantic import BaseModel, Field, field_validator
|
|
4
2
|
|
|
5
|
-
from hatchet_sdk.
|
|
3
|
+
from hatchet_sdk.clients.rest.api.workflow_api import WorkflowApi
|
|
4
|
+
from hatchet_sdk.clients.rest.api.workflow_run_api import WorkflowRunApi
|
|
5
|
+
from hatchet_sdk.clients.rest.api_client import ApiClient
|
|
6
|
+
from hatchet_sdk.clients.rest.models.create_cron_workflow_trigger_request import (
|
|
7
|
+
CreateCronWorkflowTriggerRequest,
|
|
8
|
+
)
|
|
6
9
|
from hatchet_sdk.clients.rest.models.cron_workflows import CronWorkflows
|
|
7
10
|
from hatchet_sdk.clients.rest.models.cron_workflows_list import CronWorkflowsList
|
|
8
11
|
from hatchet_sdk.clients.rest.models.cron_workflows_order_by_field import (
|
|
@@ -11,6 +14,10 @@ from hatchet_sdk.clients.rest.models.cron_workflows_order_by_field import (
|
|
|
11
14
|
from hatchet_sdk.clients.rest.models.workflow_run_order_by_direction import (
|
|
12
15
|
WorkflowRunOrderByDirection,
|
|
13
16
|
)
|
|
17
|
+
from hatchet_sdk.clients.v1.api_client import (
|
|
18
|
+
BaseRestClient,
|
|
19
|
+
maybe_additional_metadata_to_kv,
|
|
20
|
+
)
|
|
14
21
|
from hatchet_sdk.utils.typing import JSONSerializableMapping
|
|
15
22
|
|
|
16
23
|
|
|
@@ -62,27 +69,14 @@ class CreateCronTriggerConfig(BaseModel):
|
|
|
62
69
|
return v
|
|
63
70
|
|
|
64
71
|
|
|
65
|
-
class CronClient:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Attributes:
|
|
70
|
-
_client (Client): The underlying client used to interact with the REST API.
|
|
71
|
-
aio (CronClientAsync): Asynchronous counterpart of CronClient.
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
_client: Client
|
|
75
|
-
|
|
76
|
-
def __init__(self, _client: Client):
|
|
77
|
-
"""
|
|
78
|
-
Initializes the CronClient with a given Client instance.
|
|
72
|
+
class CronClient(BaseRestClient):
|
|
73
|
+
def _wra(self, client: ApiClient) -> WorkflowRunApi:
|
|
74
|
+
return WorkflowRunApi(client)
|
|
79
75
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"""
|
|
83
|
-
self._client = _client
|
|
76
|
+
def _wa(self, client: ApiClient) -> WorkflowApi:
|
|
77
|
+
return WorkflowApi(client)
|
|
84
78
|
|
|
85
|
-
def
|
|
79
|
+
async def aio_create(
|
|
86
80
|
self,
|
|
87
81
|
workflow_name: str,
|
|
88
82
|
cron_name: str,
|
|
@@ -91,7 +85,7 @@ class CronClient:
|
|
|
91
85
|
additional_metadata: JSONSerializableMapping,
|
|
92
86
|
) -> CronWorkflows:
|
|
93
87
|
"""
|
|
94
|
-
|
|
88
|
+
Asynchronously creates a new workflow cron trigger.
|
|
95
89
|
|
|
96
90
|
Args:
|
|
97
91
|
workflow_name (str): The name of the workflow to trigger.
|
|
@@ -107,38 +101,61 @@ class CronClient:
|
|
|
107
101
|
expression=expression, input=input, additional_metadata=additional_metadata
|
|
108
102
|
)
|
|
109
103
|
|
|
110
|
-
|
|
104
|
+
async with self.client() as client:
|
|
105
|
+
return await self._wra(client).cron_workflow_trigger_create(
|
|
106
|
+
tenant=self.client_config.tenant_id,
|
|
107
|
+
workflow=workflow_name,
|
|
108
|
+
create_cron_workflow_trigger_request=CreateCronWorkflowTriggerRequest(
|
|
109
|
+
cronName=cron_name,
|
|
110
|
+
cronExpression=validated_input.expression,
|
|
111
|
+
input=dict(validated_input.input),
|
|
112
|
+
additionalMetadata=dict(validated_input.additional_metadata),
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def create(
|
|
117
|
+
self,
|
|
118
|
+
workflow_name: str,
|
|
119
|
+
cron_name: str,
|
|
120
|
+
expression: str,
|
|
121
|
+
input: JSONSerializableMapping,
|
|
122
|
+
additional_metadata: JSONSerializableMapping,
|
|
123
|
+
) -> CronWorkflows:
|
|
124
|
+
return self._run_async_from_sync(
|
|
125
|
+
self.aio_create,
|
|
111
126
|
workflow_name,
|
|
112
127
|
cron_name,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
expression,
|
|
129
|
+
input,
|
|
130
|
+
additional_metadata,
|
|
116
131
|
)
|
|
117
132
|
|
|
118
|
-
def
|
|
133
|
+
async def aio_delete(self, cron_id: str) -> None:
|
|
119
134
|
"""
|
|
120
|
-
|
|
135
|
+
Asynchronously deletes a workflow cron trigger.
|
|
121
136
|
|
|
122
137
|
Args:
|
|
123
|
-
|
|
138
|
+
cron_id (str): The cron trigger ID or CronWorkflows instance to delete.
|
|
124
139
|
"""
|
|
125
|
-
self.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
)
|
|
140
|
+
async with self.client() as client:
|
|
141
|
+
await self._wa(client).workflow_cron_delete(
|
|
142
|
+
tenant=self.client_config.tenant_id, cron_workflow=str(cron_id)
|
|
143
|
+
)
|
|
130
144
|
|
|
131
|
-
def
|
|
145
|
+
def delete(self, cron_id: str) -> None:
|
|
146
|
+
return self._run_async_from_sync(self.aio_delete, cron_id)
|
|
147
|
+
|
|
148
|
+
async def aio_list(
|
|
132
149
|
self,
|
|
133
150
|
offset: int | None = None,
|
|
134
151
|
limit: int | None = None,
|
|
135
152
|
workflow_id: str | None = None,
|
|
136
|
-
additional_metadata:
|
|
153
|
+
additional_metadata: JSONSerializableMapping | None = None,
|
|
137
154
|
order_by_field: CronWorkflowsOrderByField | None = None,
|
|
138
155
|
order_by_direction: WorkflowRunOrderByDirection | None = None,
|
|
139
156
|
) -> CronWorkflowsList:
|
|
140
157
|
"""
|
|
141
|
-
|
|
158
|
+
Asynchronously retrieves a list of all workflow cron triggers matching the criteria.
|
|
142
159
|
|
|
143
160
|
Args:
|
|
144
161
|
offset (int | None): The offset to start the list from.
|
|
@@ -151,88 +168,30 @@ class CronClient:
|
|
|
151
168
|
Returns:
|
|
152
169
|
CronWorkflowsList: A list of cron workflows.
|
|
153
170
|
"""
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
Args:
|
|
168
|
-
cron_trigger (Union[str, CronWorkflows]): The cron trigger ID or CronWorkflows instance to retrieve.
|
|
169
|
-
|
|
170
|
-
Returns:
|
|
171
|
-
CronWorkflows: The requested cron workflow instance.
|
|
172
|
-
"""
|
|
173
|
-
return self._client.rest.cron_get(
|
|
174
|
-
cron_trigger.metadata.id
|
|
175
|
-
if isinstance(cron_trigger, CronWorkflows)
|
|
176
|
-
else cron_trigger
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
async def aio_create(
|
|
180
|
-
self,
|
|
181
|
-
workflow_name: str,
|
|
182
|
-
cron_name: str,
|
|
183
|
-
expression: str,
|
|
184
|
-
input: JSONSerializableMapping,
|
|
185
|
-
additional_metadata: JSONSerializableMapping,
|
|
186
|
-
) -> CronWorkflows:
|
|
187
|
-
"""
|
|
188
|
-
Asynchronously creates a new workflow cron trigger.
|
|
189
|
-
|
|
190
|
-
Args:
|
|
191
|
-
workflow_name (str): The name of the workflow to trigger.
|
|
192
|
-
cron_name (str): The name of the cron trigger.
|
|
193
|
-
expression (str): The cron expression defining the schedule.
|
|
194
|
-
input (dict): The input data for the cron workflow.
|
|
195
|
-
additional_metadata (dict[str, str]): Additional metadata associated with the cron trigger (e.g. {"key1": "value1", "key2": "value2"}).
|
|
196
|
-
|
|
197
|
-
Returns:
|
|
198
|
-
CronWorkflows: The created cron workflow instance.
|
|
199
|
-
"""
|
|
200
|
-
validated_input = CreateCronTriggerConfig(
|
|
201
|
-
expression=expression, input=input, additional_metadata=additional_metadata
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
return await self._client.rest.aio_create_cron(
|
|
205
|
-
workflow_name=workflow_name,
|
|
206
|
-
cron_name=cron_name,
|
|
207
|
-
expression=validated_input.expression,
|
|
208
|
-
input=validated_input.input,
|
|
209
|
-
additional_metadata=validated_input.additional_metadata,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
async def aio_delete(self, cron_trigger: Union[str, CronWorkflows]) -> None:
|
|
213
|
-
"""
|
|
214
|
-
Asynchronously deletes a workflow cron trigger.
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
cron_trigger (Union[str, CronWorkflows]): The cron trigger ID or CronWorkflows instance to delete.
|
|
218
|
-
"""
|
|
219
|
-
await self._client.rest.aio_delete_cron(
|
|
220
|
-
cron_trigger.metadata.id
|
|
221
|
-
if isinstance(cron_trigger, CronWorkflows)
|
|
222
|
-
else cron_trigger
|
|
223
|
-
)
|
|
171
|
+
async with self.client() as client:
|
|
172
|
+
return await self._wa(client).cron_workflow_list(
|
|
173
|
+
tenant=self.client_config.tenant_id,
|
|
174
|
+
offset=offset,
|
|
175
|
+
limit=limit,
|
|
176
|
+
workflow_id=workflow_id,
|
|
177
|
+
additional_metadata=maybe_additional_metadata_to_kv(
|
|
178
|
+
additional_metadata
|
|
179
|
+
),
|
|
180
|
+
order_by_field=order_by_field,
|
|
181
|
+
order_by_direction=order_by_direction,
|
|
182
|
+
)
|
|
224
183
|
|
|
225
|
-
|
|
184
|
+
def list(
|
|
226
185
|
self,
|
|
227
186
|
offset: int | None = None,
|
|
228
187
|
limit: int | None = None,
|
|
229
188
|
workflow_id: str | None = None,
|
|
230
|
-
additional_metadata:
|
|
189
|
+
additional_metadata: JSONSerializableMapping | None = None,
|
|
231
190
|
order_by_field: CronWorkflowsOrderByField | None = None,
|
|
232
191
|
order_by_direction: WorkflowRunOrderByDirection | None = None,
|
|
233
192
|
) -> CronWorkflowsList:
|
|
234
193
|
"""
|
|
235
|
-
|
|
194
|
+
Synchronously retrieves a list of all workflow cron triggers matching the criteria.
|
|
236
195
|
|
|
237
196
|
Args:
|
|
238
197
|
offset (int | None): The offset to start the list from.
|
|
@@ -245,7 +204,8 @@ class CronClient:
|
|
|
245
204
|
Returns:
|
|
246
205
|
CronWorkflowsList: A list of cron workflows.
|
|
247
206
|
"""
|
|
248
|
-
return
|
|
207
|
+
return self._run_async_from_sync(
|
|
208
|
+
self.aio_list,
|
|
249
209
|
offset=offset,
|
|
250
210
|
limit=limit,
|
|
251
211
|
workflow_id=workflow_id,
|
|
@@ -254,19 +214,29 @@ class CronClient:
|
|
|
254
214
|
order_by_direction=order_by_direction,
|
|
255
215
|
)
|
|
256
216
|
|
|
257
|
-
async def aio_get(self,
|
|
217
|
+
async def aio_get(self, cron_id: str) -> CronWorkflows:
|
|
258
218
|
"""
|
|
259
219
|
Asynchronously retrieves a specific workflow cron trigger by ID.
|
|
260
220
|
|
|
261
221
|
Args:
|
|
262
|
-
|
|
222
|
+
cron_id (str): The cron trigger ID or CronWorkflows instance to retrieve.
|
|
263
223
|
|
|
264
224
|
Returns:
|
|
265
225
|
CronWorkflows: The requested cron workflow instance.
|
|
266
226
|
"""
|
|
227
|
+
async with self.client() as client:
|
|
228
|
+
return await self._wa(client).workflow_cron_get(
|
|
229
|
+
tenant=self.client_config.tenant_id, cron_workflow=str(cron_id)
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def get(self, cron_id: str) -> CronWorkflows:
|
|
233
|
+
"""
|
|
234
|
+
Synchronously retrieves a specific workflow cron trigger by ID.
|
|
267
235
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
236
|
+
Args:
|
|
237
|
+
cron_id (str): The cron trigger ID or CronWorkflows instance to retrieve.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
CronWorkflows: The requested cron workflow instance.
|
|
241
|
+
"""
|
|
242
|
+
return self._run_async_from_sync(self.aio_get, cron_id)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from hatchet_sdk.clients.rest.api.log_api import LogApi
|
|
2
|
+
from hatchet_sdk.clients.rest.api_client import ApiClient
|
|
3
|
+
from hatchet_sdk.clients.rest.models.v1_log_line_list import V1LogLineList
|
|
4
|
+
from hatchet_sdk.clients.v1.api_client import BaseRestClient
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class LogsClient(BaseRestClient):
|
|
8
|
+
def _la(self, client: ApiClient) -> LogApi:
|
|
9
|
+
return LogApi(client)
|
|
10
|
+
|
|
11
|
+
async def aio_list(self, task_run_id: str) -> V1LogLineList:
|
|
12
|
+
async with self.client() as client:
|
|
13
|
+
return await self._la(client).v1_log_line_list(task=task_run_id)
|
|
14
|
+
|
|
15
|
+
def list(self, task_run_id: str) -> V1LogLineList:
|
|
16
|
+
return self._run_async_from_sync(self.aio_list, task_run_id)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from hatchet_sdk.clients.rest.api.tenant_api import TenantApi
|
|
2
|
+
from hatchet_sdk.clients.rest.api.workflow_api import WorkflowApi
|
|
3
|
+
from hatchet_sdk.clients.rest.api_client import ApiClient
|
|
4
|
+
from hatchet_sdk.clients.rest.models.tenant_queue_metrics import TenantQueueMetrics
|
|
5
|
+
from hatchet_sdk.clients.rest.models.tenant_step_run_queue_metrics import (
|
|
6
|
+
TenantStepRunQueueMetrics,
|
|
7
|
+
)
|
|
8
|
+
from hatchet_sdk.clients.rest.models.workflow_metrics import WorkflowMetrics
|
|
9
|
+
from hatchet_sdk.clients.rest.models.workflow_run_status import WorkflowRunStatus
|
|
10
|
+
from hatchet_sdk.clients.v1.api_client import (
|
|
11
|
+
BaseRestClient,
|
|
12
|
+
maybe_additional_metadata_to_kv,
|
|
13
|
+
)
|
|
14
|
+
from hatchet_sdk.utils.typing import JSONSerializableMapping
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MetricsClient(BaseRestClient):
|
|
18
|
+
def _wa(self, client: ApiClient) -> WorkflowApi:
|
|
19
|
+
return WorkflowApi(client)
|
|
20
|
+
|
|
21
|
+
def _ta(self, client: ApiClient) -> TenantApi:
|
|
22
|
+
return TenantApi(client)
|
|
23
|
+
|
|
24
|
+
async def aio_get_workflow_metrics(
|
|
25
|
+
self,
|
|
26
|
+
workflow_id: str,
|
|
27
|
+
status: WorkflowRunStatus | None = None,
|
|
28
|
+
group_key: str | None = None,
|
|
29
|
+
) -> WorkflowMetrics:
|
|
30
|
+
async with self.client() as client:
|
|
31
|
+
return await self._wa(client).workflow_get_metrics(
|
|
32
|
+
workflow=workflow_id, status=status, group_key=group_key
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def get_workflow_metrics(
|
|
36
|
+
self,
|
|
37
|
+
workflow_id: str,
|
|
38
|
+
status: WorkflowRunStatus | None = None,
|
|
39
|
+
group_key: str | None = None,
|
|
40
|
+
) -> WorkflowMetrics:
|
|
41
|
+
return self._run_async_from_sync(
|
|
42
|
+
self.aio_get_workflow_metrics, workflow_id, status, group_key
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def aio_get_queue_metrics(
|
|
46
|
+
self,
|
|
47
|
+
workflow_ids: list[str] | None = None,
|
|
48
|
+
additional_metadata: JSONSerializableMapping | None = None,
|
|
49
|
+
) -> TenantQueueMetrics:
|
|
50
|
+
async with self.client() as client:
|
|
51
|
+
return await self._wa(client).tenant_get_queue_metrics(
|
|
52
|
+
tenant=self.client_config.tenant_id,
|
|
53
|
+
workflows=workflow_ids,
|
|
54
|
+
additional_metadata=maybe_additional_metadata_to_kv(
|
|
55
|
+
additional_metadata
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def get_queue_metrics(
|
|
60
|
+
self,
|
|
61
|
+
workflow_ids: list[str] | None = None,
|
|
62
|
+
additional_metadata: JSONSerializableMapping | None = None,
|
|
63
|
+
) -> TenantQueueMetrics:
|
|
64
|
+
return self._run_async_from_sync(
|
|
65
|
+
self.aio_get_queue_metrics, workflow_ids, additional_metadata
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
async def aio_get_task_metrics(self) -> TenantStepRunQueueMetrics:
|
|
69
|
+
async with self.client() as client:
|
|
70
|
+
return await self._ta(client).tenant_get_step_run_queue_metrics(
|
|
71
|
+
tenant=self.client_config.tenant_id
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def get_task_metrics(self) -> TenantStepRunQueueMetrics:
|
|
75
|
+
return self._run_async_from_sync(self.aio_get_task_metrics)
|