hatchet-sdk 1.3.1__py3-none-any.whl → 1.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 hatchet-sdk might be problematic. Click here for more details.

@@ -42,7 +42,7 @@ class GetActionListenerRequest(BaseModel):
42
42
  worker_name: str
43
43
  services: list[str]
44
44
  actions: list[str]
45
- slots: int = 100
45
+ slots: int
46
46
  raw_labels: dict[str, str | int] = Field(default_factory=dict)
47
47
 
48
48
  labels: dict[str, WorkerLabels] = Field(default_factory=dict)
@@ -19,7 +19,7 @@ from hatchet_sdk.context.worker_context import WorkerContext
19
19
  from hatchet_sdk.features.runs import RunsClient
20
20
  from hatchet_sdk.logger import logger
21
21
  from hatchet_sdk.utils.timedelta_to_expression import Duration, timedelta_to_expr
22
- from hatchet_sdk.utils.typing import JSONSerializableMapping, WorkflowValidator
22
+ from hatchet_sdk.utils.typing import JSONSerializableMapping
23
23
  from hatchet_sdk.waits import SleepCondition, UserEventCondition
24
24
 
25
25
  if TYPE_CHECKING:
@@ -37,10 +37,9 @@ class Context:
37
37
  durable_event_listener: DurableEventListener | None,
38
38
  worker: WorkerContext,
39
39
  runs_client: RunsClient,
40
- validator_registry: dict[str, WorkflowValidator] = {},
40
+ lifespan_context: Any | None,
41
41
  ):
42
42
  self.worker = worker
43
- self.validator_registry = validator_registry
44
43
 
45
44
  self.data = action.action_payload
46
45
 
@@ -61,6 +60,8 @@ class Context:
61
60
 
62
61
  self.input = self.data.input
63
62
 
63
+ self._lifespan_context = lifespan_context
64
+
64
65
  def was_skipped(self, task: "Task[TWorkflowInput, R]") -> bool:
65
66
  return self.data.parents.get(task.name, {}).get("skipped", False)
66
67
 
@@ -74,27 +75,12 @@ class Context:
74
75
  if self.was_skipped(task):
75
76
  raise ValueError("{task.name} was skipped")
76
77
 
77
- action_prefix = self.action.action_id.split(":")[0]
78
-
79
- workflow_validator = next(
80
- (
81
- v
82
- for k, v in self.validator_registry.items()
83
- if k == f"{action_prefix}:{task.name}"
84
- ),
85
- None,
86
- )
87
-
88
78
  try:
89
79
  parent_step_data = cast(R, self.data.parents[task.name])
90
80
  except KeyError:
91
81
  raise ValueError(f"Step output for '{task.name}' not found")
92
82
 
93
- if (
94
- parent_step_data
95
- and workflow_validator
96
- and (v := workflow_validator.step_output)
97
- ):
83
+ if parent_step_data and (v := task.validators.step_output):
98
84
  return cast(R, v.model_validate(parent_step_data))
99
85
 
100
86
  return parent_step_data
@@ -133,6 +119,10 @@ class Context:
133
119
  def workflow_input(self) -> JSONSerializableMapping:
134
120
  return self.input
135
121
 
122
+ @property
123
+ def lifespan(self) -> Any:
124
+ return self._lifespan_context
125
+
136
126
  @property
137
127
  def workflow_run_id(self) -> str:
138
128
  return self.action.workflow_run_id
hatchet_sdk/hatchet.py CHANGED
@@ -33,7 +33,7 @@ from hatchet_sdk.runnables.types import (
33
33
  )
34
34
  from hatchet_sdk.runnables.workflow import BaseWorkflow, Workflow
35
35
  from hatchet_sdk.utils.timedelta_to_expression import Duration
36
- from hatchet_sdk.worker.worker import Worker
36
+ from hatchet_sdk.worker.worker import LifespanFn, Worker
37
37
 
38
38
 
39
39
  class Hatchet:
@@ -134,8 +134,10 @@ class Hatchet:
134
134
  self,
135
135
  name: str,
136
136
  slots: int = 100,
137
+ durable_slots: int = 1_000,
137
138
  labels: dict[str, str | int] = {},
138
139
  workflows: list[BaseWorkflow[Any]] = [],
140
+ lifespan: LifespanFn | None = None,
139
141
  ) -> Worker:
140
142
  """
141
143
  Create a Hatchet worker on which to run workflows.
@@ -165,11 +167,13 @@ class Hatchet:
165
167
  return Worker(
166
168
  name=name,
167
169
  slots=slots,
170
+ durable_slots=durable_slots,
168
171
  labels=labels,
169
172
  config=self._client.config,
170
173
  debug=self._client.debug,
171
174
  owned_loop=loop is None,
172
175
  workflows=workflows,
176
+ lifespan=lifespan,
173
177
  )
174
178
 
175
179
  @overload
@@ -7,6 +7,7 @@ from typing import (
7
7
  TypeVar,
8
8
  Union,
9
9
  cast,
10
+ get_type_hints,
10
11
  )
11
12
 
12
13
  from hatchet_sdk.context.context import Context, DurableContext
@@ -28,6 +29,7 @@ from hatchet_sdk.runnables.types import (
28
29
  is_sync_fn,
29
30
  )
30
31
  from hatchet_sdk.utils.timedelta_to_expression import Duration, timedelta_to_expr
32
+ from hatchet_sdk.utils.typing import TaskIOValidator, is_basemodel_subclass
31
33
  from hatchet_sdk.waits import (
32
34
  Action,
33
35
  Condition,
@@ -106,6 +108,13 @@ class Task(Generic[TWorkflowInput, R]):
106
108
  self.skip_if = self._flatten_conditions(skip_if)
107
109
  self.cancel_if = self._flatten_conditions(cancel_if)
108
110
 
111
+ return_type = get_type_hints(_fn).get("return")
112
+
113
+ self.validators: TaskIOValidator = TaskIOValidator(
114
+ workflow_input=workflow.config.input_validator,
115
+ step_output=return_type if is_basemodel_subclass(return_type) else None,
116
+ )
117
+
109
118
  def _flatten_conditions(
110
119
  self, conditions: list[Condition | OrGroup]
111
120
  ) -> list[Condition]:
@@ -1,9 +1,7 @@
1
- from typing import Any, Mapping, Type, TypeGuard, TypeVar
1
+ from typing import Any, Mapping, Type, TypeGuard
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
5
- T = TypeVar("T", bound=BaseModel)
6
-
7
5
 
8
6
  def is_basemodel_subclass(model: Any) -> TypeGuard[Type[BaseModel]]:
9
7
  try:
@@ -12,7 +10,7 @@ def is_basemodel_subclass(model: Any) -> TypeGuard[Type[BaseModel]]:
12
10
  return False
13
11
 
14
12
 
15
- class WorkflowValidator(BaseModel):
13
+ class TaskIOValidator(BaseModel):
16
14
  workflow_input: Type[BaseModel] | None = None
17
15
  step_output: Type[BaseModel] | None = None
18
16
 
@@ -8,7 +8,6 @@ from hatchet_sdk.clients.dispatcher.action_listener import Action
8
8
  from hatchet_sdk.config import ClientConfig
9
9
  from hatchet_sdk.logger import logger
10
10
  from hatchet_sdk.runnables.task import Task
11
- from hatchet_sdk.utils.typing import WorkflowValidator
12
11
  from hatchet_sdk.worker.action_listener_process import ActionEvent
13
12
  from hatchet_sdk.worker.runner.runner import Runner
14
13
  from hatchet_sdk.worker.runner.utils.capture_logs import capture_logs
@@ -24,8 +23,7 @@ class WorkerActionRunLoopManager:
24
23
  self,
25
24
  name: str,
26
25
  action_registry: dict[str, Task[Any, Any]],
27
- validator_registry: dict[str, WorkflowValidator],
28
- slots: int | None,
26
+ slots: int,
29
27
  config: ClientConfig,
30
28
  action_queue: "Queue[Action | STOP_LOOP_TYPE]",
31
29
  event_queue: "Queue[ActionEvent]",
@@ -33,10 +31,10 @@ class WorkerActionRunLoopManager:
33
31
  handle_kill: bool = True,
34
32
  debug: bool = False,
35
33
  labels: dict[str, str | int] = {},
34
+ lifespan_context: Any | None = None,
36
35
  ) -> None:
37
36
  self.name = name
38
37
  self.action_registry = action_registry
39
- self.validator_registry = validator_registry
40
38
  self.slots = slots
41
39
  self.config = config
42
40
  self.action_queue = action_queue
@@ -45,6 +43,7 @@ class WorkerActionRunLoopManager:
45
43
  self.handle_kill = handle_kill
46
44
  self.debug = debug
47
45
  self.labels = labels
46
+ self.lifespan_context = lifespan_context
48
47
 
49
48
  if self.debug:
50
49
  logger.setLevel(logging.DEBUG)
@@ -88,8 +87,8 @@ class WorkerActionRunLoopManager:
88
87
  self.slots,
89
88
  self.handle_kill,
90
89
  self.action_registry,
91
- self.validator_registry,
92
90
  self.labels,
91
+ self.lifespan_context,
93
92
  )
94
93
 
95
94
  logger.debug(f"'{self.name}' waiting for {list(self.action_registry.keys())}")
@@ -43,7 +43,6 @@ from hatchet_sdk.runnables.contextvars import (
43
43
  )
44
44
  from hatchet_sdk.runnables.task import Task
45
45
  from hatchet_sdk.runnables.types import R, TWorkflowInput
46
- from hatchet_sdk.utils.typing import WorkflowValidator
47
46
  from hatchet_sdk.worker.action_listener_process import ActionEvent
48
47
  from hatchet_sdk.worker.runner.utils.capture_logs import copy_context_vars
49
48
 
@@ -60,11 +59,11 @@ class Runner:
60
59
  self,
61
60
  event_queue: "Queue[ActionEvent]",
62
61
  config: ClientConfig,
63
- slots: int | None = None,
62
+ slots: int,
64
63
  handle_kill: bool = True,
65
64
  action_registry: dict[str, Task[TWorkflowInput, R]] = {},
66
- validator_registry: dict[str, WorkflowValidator] = {},
67
65
  labels: dict[str, str | int] = {},
66
+ lifespan_context: Any | None = None,
68
67
  ):
69
68
  # We store the config so we can dynamically create clients for the dispatcher client.
70
69
  self.config = config
@@ -73,7 +72,6 @@ class Runner:
73
72
  self.tasks: dict[str, asyncio.Task[Any]] = {} # Store run ids and futures
74
73
  self.contexts: dict[str, Context] = {} # Store run ids and contexts
75
74
  self.action_registry = action_registry
76
- self.validator_registry = validator_registry
77
75
 
78
76
  self.event_queue = event_queue
79
77
 
@@ -105,6 +103,8 @@ class Runner:
105
103
  labels=labels, client=Client(config=config).dispatcher
106
104
  )
107
105
 
106
+ self.lifespan_context = lifespan_context
107
+
108
108
  def create_workflow_run_url(self, action: Action) -> str:
109
109
  return f"{self.config.server_url}/workflow-runs/{action.workflow_run_id}?tenant={action.tenant_id}"
110
110
 
@@ -305,8 +305,8 @@ class Runner:
305
305
  event_client=self.event_client,
306
306
  durable_event_listener=self.durable_event_listener,
307
307
  worker=self.worker_context,
308
- validator_registry=self.validator_registry,
309
308
  runs_client=self.runs_client,
309
+ lifespan_context=self.lifespan_context,
310
310
  )
311
311
 
312
312
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
@@ -5,12 +5,13 @@ import os
5
5
  import re
6
6
  import signal
7
7
  import sys
8
+ from contextlib import AsyncExitStack, asynccontextmanager
8
9
  from dataclasses import dataclass, field
9
10
  from enum import Enum
10
11
  from multiprocessing import Queue
11
12
  from multiprocessing.process import BaseProcess
12
13
  from types import FrameType
13
- from typing import Any, TypeVar, get_type_hints
14
+ from typing import Any, AsyncGenerator, Callable, TypeVar
14
15
  from warnings import warn
15
16
 
16
17
  from aiohttp import web
@@ -26,7 +27,6 @@ from hatchet_sdk.contracts.v1.workflows_pb2 import CreateWorkflowVersionRequest
26
27
  from hatchet_sdk.logger import logger
27
28
  from hatchet_sdk.runnables.task import Task
28
29
  from hatchet_sdk.runnables.workflow import BaseWorkflow
29
- from hatchet_sdk.utils.typing import WorkflowValidator, is_basemodel_subclass
30
30
  from hatchet_sdk.worker.action_listener_process import (
31
31
  ActionEvent,
32
32
  worker_action_listener_process,
@@ -64,21 +64,41 @@ class HealthCheckResponse(BaseModel):
64
64
  python_version: str
65
65
 
66
66
 
67
+ LifespanGenerator = AsyncGenerator[Any, Any]
68
+ LifespanFn = Callable[[], LifespanGenerator]
69
+
70
+
71
+ @asynccontextmanager
72
+ async def _create_async_context_manager(
73
+ gen: LifespanGenerator,
74
+ ) -> AsyncGenerator[None, None]:
75
+ try:
76
+ yield
77
+ finally:
78
+ try:
79
+ await anext(gen)
80
+ except StopAsyncIteration:
81
+ pass
82
+
83
+
67
84
  class Worker:
68
85
  def __init__(
69
86
  self,
70
87
  name: str,
71
88
  config: ClientConfig,
72
- slots: int | None = None,
89
+ slots: int,
90
+ durable_slots: int,
73
91
  labels: dict[str, str | int] = {},
74
92
  debug: bool = False,
75
93
  owned_loop: bool = True,
76
94
  handle_kill: bool = True,
77
95
  workflows: list[BaseWorkflow[Any]] = [],
96
+ lifespan: LifespanFn | None = None,
78
97
  ) -> None:
79
98
  self.config = config
80
99
  self.name = self.config.namespace + name
81
100
  self.slots = slots
101
+ self.durable_slots = durable_slots
82
102
  self.debug = debug
83
103
  self.labels = labels
84
104
  self.handle_kill = handle_kill
@@ -87,8 +107,6 @@ class Worker:
87
107
  self.action_registry: dict[str, Task[Any, Any]] = {}
88
108
  self.durable_action_registry: dict[str, Task[Any, Any]] = {}
89
109
 
90
- self.validator_registry: dict[str, WorkflowValidator] = {}
91
-
92
110
  self.killing: bool = False
93
111
  self._status: WorkerStatus
94
112
 
@@ -122,6 +140,9 @@ class Worker:
122
140
  self.has_any_durable = False
123
141
  self.has_any_non_durable = False
124
142
 
143
+ self.lifespan = lifespan
144
+ self.lifespan_stack: AsyncExitStack | None = None
145
+
125
146
  self.register_workflows(workflows)
126
147
 
127
148
  def register_workflow_from_opts(self, opts: CreateWorkflowVersionRequest) -> None:
@@ -133,6 +154,11 @@ class Worker:
133
154
  sys.exit(1)
134
155
 
135
156
  def register_workflow(self, workflow: BaseWorkflow[Any]) -> None:
157
+ if not workflow.tasks:
158
+ raise ValueError(
159
+ "workflow must have at least one task registered before registering"
160
+ )
161
+
136
162
  opts = workflow.to_proto()
137
163
  name = workflow.name
138
164
 
@@ -153,13 +179,6 @@ class Worker:
153
179
  self.has_any_non_durable = True
154
180
  self.action_registry[action_name] = step
155
181
 
156
- return_type = get_type_hints(step.fn).get("return")
157
-
158
- self.validator_registry[action_name] = WorkflowValidator(
159
- workflow_input=workflow.config.input_validator,
160
- step_output=return_type if is_basemodel_subclass(return_type) else None,
161
- )
162
-
163
182
  def register_workflows(self, workflows: list[BaseWorkflow[Any]]) -> None:
164
183
  for workflow in workflows:
165
184
  self.register_workflow(workflow)
@@ -223,6 +242,11 @@ class Worker:
223
242
  logger.info(f"healthcheck server running on port {port}")
224
243
 
225
244
  def start(self, options: WorkerStartOptions = WorkerStartOptions()) -> None:
245
+ if not (self.action_registry or self.durable_action_registry):
246
+ raise ValueError(
247
+ "no actions registered, register workflows before starting worker"
248
+ )
249
+
226
250
  if options.loop is not None:
227
251
  warn(
228
252
  "Passing a custom event loop is deprecated and will be removed in the future. This option no longer has any effect",
@@ -262,15 +286,23 @@ class Worker:
262
286
  if self.config.healthcheck.enabled:
263
287
  await self._start_health_server()
264
288
 
289
+ lifespan_context = None
290
+ if self.lifespan:
291
+ lifespan_context = await self._setup_lifespan()
292
+
265
293
  if self.has_any_non_durable:
266
294
  self.action_listener_process = self._start_action_listener(is_durable=False)
267
- self.action_runner = self._run_action_runner(is_durable=False)
295
+ self.action_runner = self._run_action_runner(
296
+ is_durable=False, lifespan_context=lifespan_context
297
+ )
268
298
 
269
299
  if self.has_any_durable:
270
300
  self.durable_action_listener_process = self._start_action_listener(
271
301
  is_durable=True
272
302
  )
273
- self.durable_action_runner = self._run_action_runner(is_durable=True)
303
+ self.durable_action_runner = self._run_action_runner(
304
+ is_durable=True, lifespan_context=lifespan_context
305
+ )
274
306
 
275
307
  if self.loop:
276
308
  self.action_listener_health_check = self.loop.create_task(
@@ -279,14 +311,15 @@ class Worker:
279
311
 
280
312
  await self.action_listener_health_check
281
313
 
282
- def _run_action_runner(self, is_durable: bool) -> WorkerActionRunLoopManager:
314
+ def _run_action_runner(
315
+ self, is_durable: bool, lifespan_context: Any | None
316
+ ) -> WorkerActionRunLoopManager:
283
317
  # Retrieve the shared queue
284
318
  if self.loop:
285
319
  return WorkerActionRunLoopManager(
286
320
  self.name + ("_durable" if is_durable else ""),
287
321
  self.durable_action_registry if is_durable else self.action_registry,
288
- self.validator_registry,
289
- 1_000 if is_durable else self.slots,
322
+ self.durable_slots if is_durable else self.slots,
290
323
  self.config,
291
324
  self.durable_action_queue if is_durable else self.action_queue,
292
325
  self.durable_event_queue if is_durable else self.event_queue,
@@ -294,10 +327,31 @@ class Worker:
294
327
  self.handle_kill,
295
328
  self.client.debug,
296
329
  self.labels,
330
+ lifespan_context,
297
331
  )
298
332
 
299
333
  raise RuntimeError("event loop not set, cannot start action runner")
300
334
 
335
+ async def _setup_lifespan(self) -> Any:
336
+ if self.lifespan is None:
337
+ return None
338
+
339
+ self.lifespan_stack = AsyncExitStack()
340
+
341
+ lifespan_gen = self.lifespan()
342
+ try:
343
+ context = await anext(lifespan_gen)
344
+ await self.lifespan_stack.enter_async_context(
345
+ _create_async_context_manager(lifespan_gen)
346
+ )
347
+ return context
348
+ except StopAsyncIteration:
349
+ return None
350
+
351
+ async def _cleanup_lifespan(self) -> None:
352
+ if self.lifespan_stack is not None:
353
+ await self.lifespan_stack.aclose()
354
+
301
355
  def _start_action_listener(
302
356
  self, is_durable: bool
303
357
  ) -> multiprocessing.context.SpawnProcess:
@@ -311,7 +365,7 @@ class Worker:
311
365
  if is_durable
312
366
  else list(self.action_registry.keys())
313
367
  ),
314
- 1_000 if is_durable else self.slots,
368
+ self.durable_slots if is_durable else self.slots,
315
369
  self.config,
316
370
  self.durable_action_queue if is_durable else self.action_queue,
317
371
  self.durable_event_queue if is_durable else self.event_queue,
@@ -405,6 +459,8 @@ class Worker:
405
459
  ):
406
460
  self.durable_action_listener_process.kill()
407
461
 
462
+ await self._cleanup_lifespan()
463
+
408
464
  await self._close()
409
465
  if self.loop and self.owned_loop:
410
466
  self.loop.stop()
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hatchet-sdk
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Summary:
5
+ License: MIT
5
6
  Author: Alexander Belanger
6
7
  Author-email: alexander@hatchet.run
7
8
  Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
8
10
  Classifier: Programming Language :: Python :: 3
9
11
  Classifier: Programming Language :: Python :: 3.10
10
12
  Classifier: Programming Language :: Python :: 3.11
@@ -1,7 +1,7 @@
1
1
  hatchet_sdk/__init__.py,sha256=LUj6VyGVSHCYTQTaoyiVhjyJLOfv6gMCmb-s4hRyISM,10031
2
2
  hatchet_sdk/client.py,sha256=tbOeMuaJmgpyYSQg8QUz_J4AdqRNvV9E0aEZpgsiZTE,2207
3
3
  hatchet_sdk/clients/admin.py,sha256=qY9-nB8o-jCpQQF65nooemH8HOioXjntp9ethpGke9o,17266
4
- hatchet_sdk/clients/dispatcher/action_listener.py,sha256=sAboL2Dr59MAPBR3KcJ7sSBfOwnTR3rdsRTJ0bDRuuc,16279
4
+ hatchet_sdk/clients/dispatcher/action_listener.py,sha256=yJhHqnp_RAhUfOJUpBCLIpqMyXaLX-CSUsm0TgPxGEs,16273
5
5
  hatchet_sdk/clients/dispatcher/dispatcher.py,sha256=IL-hDXG8Lzas9FieVuNr47E_3Gvpc-aL4Xu_l385Vp8,8140
6
6
  hatchet_sdk/clients/event_ts.py,sha256=OjYc_y1K3fNNZ7QLRJYBDnfgsyUVERkxofYldO4QVVs,1672
7
7
  hatchet_sdk/clients/events.py,sha256=sKqzGwkrW_AKWW0Q_rxfwo9jXV5EUpLx7fTQvCNHaVo,5443
@@ -221,7 +221,7 @@ hatchet_sdk/clients/v1/api_client.py,sha256=mJQUZ3cOxlFJiwWKK5F8jBxcpNZ7A2292Huc
221
221
  hatchet_sdk/config.py,sha256=jJA76BOvVdfOQHy6TKclAvr2qyblcM-Pz5J-hVAdpQ4,3588
222
222
  hatchet_sdk/connection.py,sha256=B5gT5NL9BBB5-l9U_cN6pMlraQk880rEYMnqaK_dgL0,2590
223
223
  hatchet_sdk/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
224
- hatchet_sdk/context/context.py,sha256=FUClTuxFETBAljI0gknOdqkCEgkY2EX1lOx2xib2xzk,9659
224
+ hatchet_sdk/context/context.py,sha256=DWaHE3AuXFvRKPxYaKW5-CUY8R9lz-lF4t3sgucwZPs,9336
225
225
  hatchet_sdk/context/worker_context.py,sha256=OVcEWvdT_Kpd0nlg61VAPUgIPSFzSLs0aSrXWj-1GX4,974
226
226
  hatchet_sdk/contracts/dispatcher_pb2.py,sha256=SN4CIKeQwYkrbfRGhdhZo2uBn4nGzjUWIC1vvXdDeOQ,14503
227
227
  hatchet_sdk/contracts/dispatcher_pb2.pyi,sha256=ZSGio5eYxkw-QuQx2C5ASTNcKzeMQn5JTnWaRiThafM,18455
@@ -250,7 +250,7 @@ hatchet_sdk/features/runs.py,sha256=2069-4YUaouYloFUxa3-WmtkWhCjEIGMeGrN_nlnYCA,
250
250
  hatchet_sdk/features/scheduled.py,sha256=1_GMP7jSC9UCFFWLVES5HtTGQInQd9cJeqJDhq0Hnmg,8813
251
251
  hatchet_sdk/features/workers.py,sha256=fG8zoRXMm-lNNdNfeovKKpmJ0RzjZd6CIq_dVsu-ih0,1515
252
252
  hatchet_sdk/features/workflows.py,sha256=x1Z_HZM_ZQZbWZhOfzJaEiPfRNSn6YX3IaTmFZ5D7MY,2069
253
- hatchet_sdk/hatchet.py,sha256=7wDYLGBlPdQ0IvnJUdAe8Ms2B9IZWpedRED4AflZCW0,22982
253
+ hatchet_sdk/hatchet.py,sha256=oHE27SRgYddR1KiJyQwGAa0eV_uEH73w4_jbXxFIUqU,23146
254
254
  hatchet_sdk/labels.py,sha256=nATgxWE3lFxRTnfISEpoIRLGbMfAZsHF4lZTuG4Mfic,182
255
255
  hatchet_sdk/logger.py,sha256=5uOr52T4mImSQm1QvWT8HvZFK5WfPNh3Y1cBQZRFgUQ,333
256
256
  hatchet_sdk/metadata.py,sha256=XkRbhnghJJGCdVvF-uzyGBcNaTqpeQ3uiQvNNP1wyBc,107
@@ -259,14 +259,14 @@ hatchet_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
259
259
  hatchet_sdk/rate_limit.py,sha256=TwbCuggiZaWpYuo4mjVLlE-z1OfQ2mRBiVvCSaG3lv4,3919
260
260
  hatchet_sdk/runnables/contextvars.py,sha256=6MDocAMmlyiRW37oQ1jyx10tAlJs-xgDjR3xPoPz05g,426
261
261
  hatchet_sdk/runnables/standalone.py,sha256=KyKA3UeuyU_IK0t-c0Q56Lm-W4rewILkfHlenjos474,6276
262
- hatchet_sdk/runnables/task.py,sha256=R7QpxHsMKQSp6V84NeQ8oFdTNLPY77Ocx0MM1Q3xX40,7164
262
+ hatchet_sdk/runnables/task.py,sha256=nZPclBbNaYRMlCLOYi91YU503MiTcGSp92Unh3_nKvs,7533
263
263
  hatchet_sdk/runnables/types.py,sha256=1Y2mS7bDVY86rE7SSMzt9KKcF8qGiaiEmQ85jR8DMT4,4500
264
264
  hatchet_sdk/runnables/workflow.py,sha256=FcmN7-cmI32GnnkKGKhUL2xV3z7vfBK43LmJVuKKiyo,27771
265
265
  hatchet_sdk/token.py,sha256=KjIiInwG5Kqd_FO4BSW1x_5Uc7PFbnzIVJqr50-ZldE,779
266
266
  hatchet_sdk/utils/backoff.py,sha256=6B5Rb5nLKw_TqqgpJMYjIBV1PTTtbOMRZCveisVhg_I,353
267
267
  hatchet_sdk/utils/proto_enums.py,sha256=0UybwE3s7TcqmzoQSO8YnhgAKOS8WZXsyPchB8-eksw,1247
268
268
  hatchet_sdk/utils/timedelta_to_expression.py,sha256=n5jIxlcswN9GwFPjktuMceedekzWWT6X7U6gbsZciIQ,455
269
- hatchet_sdk/utils/typing.py,sha256=ohzSvBciQKiFwY-rCWdpodEZb4iAilQ87rjOBakY4MQ,473
269
+ hatchet_sdk/utils/typing.py,sha256=huflXWR7fvRfIFYdqQIrQmn9jtukzOWoTpW3AXGk5c0,427
270
270
  hatchet_sdk/v0/__init__.py,sha256=YNh-0rPHS0rcphmykJ1N2NMfgvERF4oJpBtx3IH_E_M,9657
271
271
  hatchet_sdk/v0/client.py,sha256=G1RDZln9Og7tRQulogXkZw8TsVlx7f0VvmtFI_VAe6E,3495
272
272
  hatchet_sdk/v0/clients/admin.py,sha256=l6fW21p_3pROz8mVB2QOXX0Pg5poeLXcBNEm6Uids30,18071
@@ -501,12 +501,12 @@ hatchet_sdk/v0/workflow_run.py,sha256=jsEZprXshrSV7i_TtL5uoCL03D18zQ3NeJCq7mp97D
501
501
  hatchet_sdk/waits.py,sha256=dTrelK8Lk0W5anq3TlpJwAK5z8TJ0FW7XgoSg8bf8fA,3351
502
502
  hatchet_sdk/worker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
503
503
  hatchet_sdk/worker/action_listener_process.py,sha256=KxS7-wBpfKnsq0LNSvk-MG442Lh60iQMy3VpD1FW3mU,11703
504
- hatchet_sdk/worker/runner/run_loop_manager.py,sha256=P0iyKSfAb0IW5LDUnwzUOgCp0lPpAAKXCkeTXGQq8oY,3893
505
- hatchet_sdk/worker/runner/runner.py,sha256=mfEsR2EDcKPkEIylkz3FLsMC33OqTs4r5zpxCIjitoc,17446
504
+ hatchet_sdk/worker/runner/run_loop_manager.py,sha256=RNWKDCjR57nJ0LCoLUMi0_3pnmpqyo80mz_RaxHYGIc,3812
505
+ hatchet_sdk/worker/runner/runner.py,sha256=J-gTpoYF9WphB1zZhpPJryCv10VjU-MiCdJgMYH-nds,17352
506
506
  hatchet_sdk/worker/runner/utils/capture_logs.py,sha256=nHRPSiDBqzhObM7i2X7t03OupVFnE7kQBdR2Ckgg-2w,2709
507
- hatchet_sdk/worker/worker.py,sha256=dcJEMeogodhLEi_5a0ldJLZ5EEN7DNcr8aiFLknTb18,14667
507
+ hatchet_sdk/worker/worker.py,sha256=m11u3QPyAqXJpF6Y3lTUEVqTKdIigGKTXTymNPqq6hw,16149
508
508
  hatchet_sdk/workflow_run.py,sha256=ZwH0HLFGFVXz6jbiqSv4w0Om2XuR52Tzzw6LH4y65jQ,2765
509
- hatchet_sdk-1.3.1.dist-info/METADATA,sha256=sS8Lrxkr6HvdjuhsP0vmjACIGE_pXxfGBH6uyzvgF1M,3571
510
- hatchet_sdk-1.3.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
511
- hatchet_sdk-1.3.1.dist-info/entry_points.txt,sha256=5mTp_AsCWK5raiVxP_MU9eBCgkRGl4OsN6chpHcvm7o,1235
512
- hatchet_sdk-1.3.1.dist-info/RECORD,,
509
+ hatchet_sdk-1.4.0.dist-info/METADATA,sha256=4-0m7YVw0La3uVvIk9d2OpuCwZAoVuA1XOAZ9vhtnC0,3635
510
+ hatchet_sdk-1.4.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
511
+ hatchet_sdk-1.4.0.dist-info/entry_points.txt,sha256=uYc-ivF7fUATjrWnwHP32ojgMCmogIs6yFOU8lEA4mk,1276
512
+ hatchet_sdk-1.4.0.dist-info/RECORD,,
@@ -14,6 +14,7 @@ events=examples.events.worker:main
14
14
  existing_loop=examples.worker_existing_loop.worker:main
15
15
  fanout=examples.fanout.worker:main
16
16
  fanout_sync=examples.fanout_sync.worker:main
17
+ lifespans=examples.lifespans.worker:main
17
18
  logger=examples.logger.worker:main
18
19
  manual_trigger=examples.manual_trigger.worker:main
19
20
  on_failure=examples.on_failure.worker:main