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 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)
@@ -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[Dict[str, Any]] = None
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()
@@ -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: str = action.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.
@@ -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.client import Client
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
- Client for managing workflow cron triggers synchronously.
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
- Args:
81
- _client (Client): The client instance to be used for REST interactions.
82
- """
83
- self._client = _client
76
+ def _wa(self, client: ApiClient) -> WorkflowApi:
77
+ return WorkflowApi(client)
84
78
 
85
- def create(
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
- Creates a new workflow cron trigger.
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
- return self._client.rest.cron_create(
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
- validated_input.expression,
114
- validated_input.input,
115
- validated_input.additional_metadata,
128
+ expression,
129
+ input,
130
+ additional_metadata,
116
131
  )
117
132
 
118
- def delete(self, cron_trigger: Union[str, CronWorkflows]) -> None:
133
+ async def aio_delete(self, cron_id: str) -> None:
119
134
  """
120
- Deletes a workflow cron trigger.
135
+ Asynchronously deletes a workflow cron trigger.
121
136
 
122
137
  Args:
123
- cron_trigger (Union[str, CronWorkflows]): The cron trigger ID or CronWorkflows instance to delete.
138
+ cron_id (str): The cron trigger ID or CronWorkflows instance to delete.
124
139
  """
125
- self._client.rest.cron_delete(
126
- cron_trigger.metadata.id
127
- if isinstance(cron_trigger, CronWorkflows)
128
- else cron_trigger
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 list(
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: list[str] | None = None,
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
- Retrieves a list of all workflow cron triggers matching the criteria.
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
- return self._client.rest.cron_list(
155
- offset=offset,
156
- limit=limit,
157
- workflow_id=workflow_id,
158
- additional_metadata=additional_metadata,
159
- order_by_field=order_by_field,
160
- order_by_direction=order_by_direction,
161
- )
162
-
163
- def get(self, cron_trigger: Union[str, CronWorkflows]) -> CronWorkflows:
164
- """
165
- Retrieves a specific workflow cron trigger by ID.
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
- async def aio_list(
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: List[str] | None = None,
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
- Asynchronously retrieves a list of all workflow cron triggers matching the criteria.
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 await self._client.rest.aio_list_crons(
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, cron_trigger: Union[str, CronWorkflows]) -> CronWorkflows:
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
- cron_trigger (Union[str, CronWorkflows]): The cron trigger ID or CronWorkflows instance to retrieve.
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
- return await self._client.rest.aio_get_cron(
269
- cron_trigger.metadata.id
270
- if isinstance(cron_trigger, CronWorkflows)
271
- else cron_trigger
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)