hatchet-sdk 1.12.3__py3-none-any.whl → 1.14.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.

Files changed (83) hide show
  1. hatchet_sdk/__init__.py +54 -40
  2. hatchet_sdk/clients/admin.py +18 -23
  3. hatchet_sdk/clients/dispatcher/action_listener.py +4 -3
  4. hatchet_sdk/clients/dispatcher/dispatcher.py +1 -4
  5. hatchet_sdk/clients/event_ts.py +2 -1
  6. hatchet_sdk/clients/events.py +16 -12
  7. hatchet_sdk/clients/listeners/durable_event_listener.py +4 -2
  8. hatchet_sdk/clients/listeners/pooled_listener.py +2 -2
  9. hatchet_sdk/clients/listeners/run_event_listener.py +7 -8
  10. hatchet_sdk/clients/listeners/workflow_listener.py +14 -6
  11. hatchet_sdk/clients/rest/api_response.py +3 -2
  12. hatchet_sdk/clients/rest/models/semaphore_slots.py +1 -1
  13. hatchet_sdk/clients/rest/models/v1_task_summary.py +5 -0
  14. hatchet_sdk/clients/rest/models/v1_workflow_run_details.py +11 -1
  15. hatchet_sdk/clients/rest/models/workflow_version.py +5 -0
  16. hatchet_sdk/clients/rest/tenacity_utils.py +6 -8
  17. hatchet_sdk/config.py +2 -0
  18. hatchet_sdk/connection.py +10 -4
  19. hatchet_sdk/context/context.py +170 -46
  20. hatchet_sdk/context/worker_context.py +4 -7
  21. hatchet_sdk/contracts/dispatcher_pb2.py +38 -38
  22. hatchet_sdk/contracts/dispatcher_pb2.pyi +4 -2
  23. hatchet_sdk/contracts/events_pb2.py +13 -13
  24. hatchet_sdk/contracts/events_pb2.pyi +4 -2
  25. hatchet_sdk/contracts/v1/workflows_pb2.py +1 -1
  26. hatchet_sdk/contracts/v1/workflows_pb2.pyi +2 -2
  27. hatchet_sdk/exceptions.py +103 -1
  28. hatchet_sdk/features/cron.py +2 -2
  29. hatchet_sdk/features/filters.py +12 -21
  30. hatchet_sdk/features/runs.py +4 -4
  31. hatchet_sdk/features/scheduled.py +8 -9
  32. hatchet_sdk/hatchet.py +65 -64
  33. hatchet_sdk/opentelemetry/instrumentor.py +20 -20
  34. hatchet_sdk/runnables/action.py +1 -2
  35. hatchet_sdk/runnables/contextvars.py +19 -0
  36. hatchet_sdk/runnables/task.py +37 -29
  37. hatchet_sdk/runnables/types.py +9 -8
  38. hatchet_sdk/runnables/workflow.py +57 -42
  39. hatchet_sdk/utils/proto_enums.py +4 -4
  40. hatchet_sdk/utils/timedelta_to_expression.py +2 -3
  41. hatchet_sdk/utils/typing.py +11 -17
  42. hatchet_sdk/v0/__init__.py +7 -7
  43. hatchet_sdk/v0/clients/admin.py +7 -7
  44. hatchet_sdk/v0/clients/dispatcher/action_listener.py +8 -8
  45. hatchet_sdk/v0/clients/dispatcher/dispatcher.py +9 -9
  46. hatchet_sdk/v0/clients/events.py +3 -3
  47. hatchet_sdk/v0/clients/rest/tenacity_utils.py +1 -1
  48. hatchet_sdk/v0/clients/run_event_listener.py +3 -3
  49. hatchet_sdk/v0/clients/workflow_listener.py +5 -5
  50. hatchet_sdk/v0/context/context.py +6 -6
  51. hatchet_sdk/v0/hatchet.py +4 -4
  52. hatchet_sdk/v0/opentelemetry/instrumentor.py +1 -1
  53. hatchet_sdk/v0/rate_limit.py +1 -1
  54. hatchet_sdk/v0/v2/callable.py +4 -4
  55. hatchet_sdk/v0/v2/concurrency.py +2 -2
  56. hatchet_sdk/v0/v2/hatchet.py +3 -3
  57. hatchet_sdk/v0/worker/action_listener_process.py +6 -6
  58. hatchet_sdk/v0/worker/runner/run_loop_manager.py +1 -1
  59. hatchet_sdk/v0/worker/runner/runner.py +10 -10
  60. hatchet_sdk/v0/worker/runner/utils/capture_logs.py +1 -1
  61. hatchet_sdk/v0/worker/worker.py +2 -2
  62. hatchet_sdk/v0/workflow.py +3 -3
  63. hatchet_sdk/waits.py +6 -5
  64. hatchet_sdk/worker/action_listener_process.py +33 -13
  65. hatchet_sdk/worker/runner/run_loop_manager.py +15 -11
  66. hatchet_sdk/worker/runner/runner.py +142 -80
  67. hatchet_sdk/worker/runner/utils/capture_logs.py +72 -31
  68. hatchet_sdk/worker/worker.py +30 -26
  69. hatchet_sdk/workflow_run.py +4 -2
  70. {hatchet_sdk-1.12.3.dist-info → hatchet_sdk-1.14.0.dist-info}/METADATA +1 -1
  71. {hatchet_sdk-1.12.3.dist-info → hatchet_sdk-1.14.0.dist-info}/RECORD +73 -83
  72. hatchet_sdk/v0/contracts/dispatcher_pb2.py +0 -102
  73. hatchet_sdk/v0/contracts/dispatcher_pb2.pyi +0 -387
  74. hatchet_sdk/v0/contracts/dispatcher_pb2_grpc.py +0 -621
  75. hatchet_sdk/v0/contracts/events_pb2.py +0 -46
  76. hatchet_sdk/v0/contracts/events_pb2.pyi +0 -87
  77. hatchet_sdk/v0/contracts/events_pb2_grpc.py +0 -274
  78. hatchet_sdk/v0/contracts/workflows_pb2.py +0 -80
  79. hatchet_sdk/v0/contracts/workflows_pb2.pyi +0 -312
  80. hatchet_sdk/v0/contracts/workflows_pb2_grpc.py +0 -277
  81. hatchet_sdk/v0/logger.py +0 -13
  82. {hatchet_sdk-1.12.3.dist-info → hatchet_sdk-1.14.0.dist-info}/WHEEL +0 -0
  83. {hatchet_sdk-1.12.3.dist-info → hatchet_sdk-1.14.0.dist-info}/entry_points.txt +0 -0
@@ -11,9 +11,7 @@ from typing import (
11
11
  Union,
12
12
  )
13
13
 
14
- from hatchet_sdk.v0.clients.admin import ChildTriggerWorkflowOptions
15
- from hatchet_sdk.v0.context.context import Context
16
- from hatchet_sdk.v0.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
14
+ from hatchet_sdk.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
17
15
  CreateStepRateLimit,
18
16
  CreateWorkflowJobOpts,
19
17
  CreateWorkflowStepOpts,
@@ -23,8 +21,10 @@ from hatchet_sdk.v0.contracts.workflows_pb2 import ( # type: ignore[attr-define
23
21
  WorkflowConcurrencyOpts,
24
22
  WorkflowKind,
25
23
  )
24
+ from hatchet_sdk.logger import logger
25
+ from hatchet_sdk.v0.clients.admin import ChildTriggerWorkflowOptions
26
+ from hatchet_sdk.v0.context.context import Context
26
27
  from hatchet_sdk.v0.labels import DesiredWorkerLabel
27
- from hatchet_sdk.v0.logger import logger
28
28
  from hatchet_sdk.v0.rate_limit import RateLimit
29
29
  from hatchet_sdk.v0.v2.concurrency import ConcurrencyFunction
30
30
  from hatchet_sdk.v0.workflow_run import RunRef
@@ -1,9 +1,9 @@
1
1
  from typing import Any, Callable
2
2
 
3
- from hatchet_sdk.v0.context.context import Context
4
- from hatchet_sdk.v0.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
3
+ from hatchet_sdk.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
5
4
  ConcurrencyLimitStrategy,
6
5
  )
6
+ from hatchet_sdk.v0.context.context import Context
7
7
 
8
8
 
9
9
  class ConcurrencyFunction:
@@ -1,11 +1,11 @@
1
1
  from typing import Any, Callable, TypeVar, Union
2
2
 
3
- from hatchet_sdk.v0 import Worker
4
- from hatchet_sdk.v0.context.context import Context
5
- from hatchet_sdk.v0.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
3
+ from hatchet_sdk.contracts.workflows_pb2 import ( # type: ignore[attr-defined]
6
4
  ConcurrencyLimitStrategy,
7
5
  StickyStrategy,
8
6
  )
7
+ from hatchet_sdk.v0 import Worker
8
+ from hatchet_sdk.v0.context.context import Context
9
9
  from hatchet_sdk.v0.hatchet import Hatchet as HatchetV1
10
10
  from hatchet_sdk.v0.hatchet import workflow
11
11
  from hatchet_sdk.v0.labels import DesiredWorkerLabel
@@ -8,6 +8,12 @@ from typing import Any, List, Mapping, Optional
8
8
 
9
9
  import grpc
10
10
 
11
+ from hatchet_sdk.contracts.dispatcher_pb2 import (
12
+ GROUP_KEY_EVENT_TYPE_STARTED,
13
+ STEP_EVENT_TYPE_STARTED,
14
+ ActionType,
15
+ )
16
+ from hatchet_sdk.logger import logger
11
17
  from hatchet_sdk.v0.client import Client, new_client_raw
12
18
  from hatchet_sdk.v0.clients.dispatcher.action_listener import Action
13
19
  from hatchet_sdk.v0.clients.dispatcher.dispatcher import (
@@ -16,13 +22,7 @@ from hatchet_sdk.v0.clients.dispatcher.dispatcher import (
16
22
  new_dispatcher,
17
23
  )
18
24
  from hatchet_sdk.v0.clients.rest.models.update_worker_request import UpdateWorkerRequest
19
- from hatchet_sdk.v0.contracts.dispatcher_pb2 import (
20
- GROUP_KEY_EVENT_TYPE_STARTED,
21
- STEP_EVENT_TYPE_STARTED,
22
- ActionType,
23
- )
24
25
  from hatchet_sdk.v0.loader import ClientConfig
25
- from hatchet_sdk.v0.logger import logger
26
26
  from hatchet_sdk.v0.utils.backoff import exp_backoff_sleep
27
27
 
28
28
  ACTION_EVENT_RETRY_COUNT = 5
@@ -4,11 +4,11 @@ from dataclasses import dataclass, field
4
4
  from multiprocessing import Queue
5
5
  from typing import Callable, TypeVar
6
6
 
7
+ from hatchet_sdk.logger import logger
7
8
  from hatchet_sdk.v0 import Context
8
9
  from hatchet_sdk.v0.client import Client, new_client_raw
9
10
  from hatchet_sdk.v0.clients.dispatcher.action_listener import Action
10
11
  from hatchet_sdk.v0.loader import ClientConfig
11
- from hatchet_sdk.v0.logger import logger
12
12
  from hatchet_sdk.v0.utils.types import WorkflowValidator
13
13
  from hatchet_sdk.v0.worker.runner.runner import Runner
14
14
  from hatchet_sdk.v0.worker.runner.utils.capture_logs import capture_logs
@@ -13,15 +13,7 @@ from typing import Any, Callable, Dict, cast
13
13
 
14
14
  from pydantic import BaseModel
15
15
 
16
- from hatchet_sdk.v0.client import new_client_raw
17
- from hatchet_sdk.v0.clients.admin import new_admin
18
- from hatchet_sdk.v0.clients.dispatcher.action_listener import Action
19
- from hatchet_sdk.v0.clients.dispatcher.dispatcher import new_dispatcher
20
- from hatchet_sdk.v0.clients.run_event_listener import new_listener
21
- from hatchet_sdk.v0.clients.workflow_listener import PooledWorkflowRunListener
22
- from hatchet_sdk.v0.context import Context # type: ignore[attr-defined]
23
- from hatchet_sdk.v0.context.worker_context import WorkerContext
24
- from hatchet_sdk.v0.contracts.dispatcher_pb2 import (
16
+ from hatchet_sdk.contracts.dispatcher_pb2 import (
25
17
  GROUP_KEY_EVENT_TYPE_COMPLETED,
26
18
  GROUP_KEY_EVENT_TYPE_FAILED,
27
19
  GROUP_KEY_EVENT_TYPE_STARTED,
@@ -30,8 +22,16 @@ from hatchet_sdk.v0.contracts.dispatcher_pb2 import (
30
22
  STEP_EVENT_TYPE_STARTED,
31
23
  ActionType,
32
24
  )
25
+ from hatchet_sdk.logger import logger
26
+ from hatchet_sdk.v0.client import new_client_raw
27
+ from hatchet_sdk.v0.clients.admin import new_admin
28
+ from hatchet_sdk.v0.clients.dispatcher.action_listener import Action
29
+ from hatchet_sdk.v0.clients.dispatcher.dispatcher import new_dispatcher
30
+ from hatchet_sdk.v0.clients.run_event_listener import new_listener
31
+ from hatchet_sdk.v0.clients.workflow_listener import PooledWorkflowRunListener
32
+ from hatchet_sdk.v0.context import Context # type: ignore[attr-defined]
33
+ from hatchet_sdk.v0.context.worker_context import WorkerContext
33
34
  from hatchet_sdk.v0.loader import ClientConfig
34
- from hatchet_sdk.v0.logger import logger
35
35
  from hatchet_sdk.v0.utils.types import WorkflowValidator
36
36
  from hatchet_sdk.v0.v2.callable import DurableContext
37
37
  from hatchet_sdk.v0.worker.action_listener_process import ActionEvent
@@ -5,7 +5,7 @@ from concurrent.futures import ThreadPoolExecutor
5
5
  from io import StringIO
6
6
  from typing import Any, Coroutine
7
7
 
8
- from hatchet_sdk.v0 import logger
8
+ from hatchet_sdk import logger
9
9
  from hatchet_sdk.v0.clients.events import EventClient
10
10
 
11
11
  wr: contextvars.ContextVar[str | None] = contextvars.ContextVar(
@@ -17,11 +17,11 @@ from aiohttp.web_request import Request
17
17
  from aiohttp.web_response import Response
18
18
  from prometheus_client import CONTENT_TYPE_LATEST, Gauge, generate_latest
19
19
 
20
+ from hatchet_sdk.contracts.workflows_pb2 import CreateWorkflowVersionOpts
21
+ from hatchet_sdk.logger import logger
20
22
  from hatchet_sdk.v0 import Context
21
23
  from hatchet_sdk.v0.client import Client, new_client_raw
22
- from hatchet_sdk.v0.contracts.workflows_pb2 import CreateWorkflowVersionOpts
23
24
  from hatchet_sdk.v0.loader import ClientConfig
24
- from hatchet_sdk.v0.logger import logger
25
25
  from hatchet_sdk.v0.utils.types import WorkflowValidator
26
26
  from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
27
27
  from hatchet_sdk.v0.v2.callable import HatchetCallable
@@ -13,8 +13,7 @@ from typing import (
13
13
 
14
14
  from pydantic import BaseModel
15
15
 
16
- from hatchet_sdk.v0 import ConcurrencyLimitStrategy
17
- from hatchet_sdk.v0.contracts.workflows_pb2 import (
16
+ from hatchet_sdk.contracts.workflows_pb2 import (
18
17
  CreateWorkflowJobOpts,
19
18
  CreateWorkflowStepOpts,
20
19
  CreateWorkflowVersionOpts,
@@ -22,7 +21,8 @@ from hatchet_sdk.v0.contracts.workflows_pb2 import (
22
21
  WorkflowConcurrencyOpts,
23
22
  WorkflowKind,
24
23
  )
25
- from hatchet_sdk.v0.logger import logger
24
+ from hatchet_sdk.logger import logger
25
+ from hatchet_sdk.v0 import ConcurrencyLimitStrategy
26
26
  from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
27
27
 
28
28
 
hatchet_sdk/waits.py CHANGED
@@ -6,6 +6,7 @@ from uuid import uuid4
6
6
 
7
7
  from pydantic import BaseModel, Field
8
8
 
9
+ from hatchet_sdk.config import ClientConfig
9
10
  from hatchet_sdk.contracts.v1.shared.condition_pb2 import Action as ProtoAction
10
11
  from hatchet_sdk.contracts.v1.shared.condition_pb2 import (
11
12
  BaseMatchCondition,
@@ -53,7 +54,7 @@ class Condition(ABC):
53
54
 
54
55
  @abstractmethod
55
56
  def to_proto(
56
- self,
57
+ self, config: ClientConfig
57
58
  ) -> UserEventMatchCondition | ParentOverrideMatchCondition | SleepMatchCondition:
58
59
  pass
59
60
 
@@ -71,7 +72,7 @@ class SleepCondition(Condition):
71
72
 
72
73
  self.duration = duration
73
74
 
74
- def to_proto(self) -> SleepMatchCondition:
75
+ def to_proto(self, config: ClientConfig) -> SleepMatchCondition:
75
76
  return SleepMatchCondition(
76
77
  base=self.base.to_proto(),
77
78
  sleep_for=timedelta_to_expr(self.duration),
@@ -95,10 +96,10 @@ class UserEventCondition(Condition):
95
96
  self.event_key = event_key
96
97
  self.expression = expression
97
98
 
98
- def to_proto(self) -> UserEventMatchCondition:
99
+ def to_proto(self, config: ClientConfig) -> UserEventMatchCondition:
99
100
  return UserEventMatchCondition(
100
101
  base=self.base.to_proto(),
101
- user_event_key=self.event_key,
102
+ user_event_key=config.apply_namespace(self.event_key),
102
103
  )
103
104
 
104
105
 
@@ -124,7 +125,7 @@ class ParentCondition(Condition):
124
125
 
125
126
  self.parent = parent
126
127
 
127
- def to_proto(self) -> ParentOverrideMatchCondition:
128
+ def to_proto(self, config: ClientConfig) -> ParentOverrideMatchCondition:
128
129
  return ParentOverrideMatchCondition(
129
130
  base=self.base.to_proto(),
130
131
  parent_readable_id=self.parent.name,
@@ -4,9 +4,10 @@ import signal
4
4
  import time
5
5
  from dataclasses import dataclass
6
6
  from multiprocessing import Queue
7
- from typing import Any, Literal
7
+ from typing import Any
8
8
 
9
9
  import grpc
10
+ from grpc.aio import UnaryUnaryCall
10
11
 
11
12
  from hatchet_sdk.client import Client
12
13
  from hatchet_sdk.clients.dispatcher.action_listener import (
@@ -19,6 +20,9 @@ from hatchet_sdk.config import ClientConfig
19
20
  from hatchet_sdk.contracts.dispatcher_pb2 import (
20
21
  GROUP_KEY_EVENT_TYPE_STARTED,
21
22
  STEP_EVENT_TYPE_STARTED,
23
+ ActionEventResponse,
24
+ GroupKeyActionEvent,
25
+ StepActionEvent,
22
26
  )
23
27
  from hatchet_sdk.logger import logger
24
28
  from hatchet_sdk.runnables.action import Action, ActionType
@@ -29,6 +33,7 @@ from hatchet_sdk.runnables.contextvars import (
29
33
  ctx_workflow_run_id,
30
34
  )
31
35
  from hatchet_sdk.utils.backoff import exp_backoff_sleep
36
+ from hatchet_sdk.utils.typing import STOP_LOOP, STOP_LOOP_TYPE
32
37
 
33
38
  ACTION_EVENT_RETRY_COUNT = 5
34
39
 
@@ -41,9 +46,6 @@ class ActionEvent:
41
46
  should_not_retry: bool
42
47
 
43
48
 
44
- STOP_LOOP_TYPE = Literal["STOP_LOOP"]
45
- STOP_LOOP: STOP_LOOP_TYPE = "STOP_LOOP" # Sentinel object to stop the loop
46
-
47
49
  BLOCKED_THREAD_WARNING = "THE TIME TO START THE TASK RUN IS TOO LONG, THE EVENT LOOP MAY BE BLOCKED. See https://docs.hatchet.run/blog/warning-event-loop-blocked for details and debugging help."
48
50
 
49
51
 
@@ -56,9 +58,9 @@ class WorkerActionListenerProcess:
56
58
  config: ClientConfig,
57
59
  action_queue: "Queue[Action]",
58
60
  event_queue: "Queue[ActionEvent | STOP_LOOP_TYPE]",
59
- handle_kill: bool = True,
60
- debug: bool = False,
61
- labels: dict[str, str | int] = {},
61
+ handle_kill: bool,
62
+ debug: bool,
63
+ labels: dict[str, str | int],
62
64
  ) -> None:
63
65
  self.name = name
64
66
  self.actions = actions
@@ -75,6 +77,14 @@ class WorkerActionListenerProcess:
75
77
  self.action_loop_task: asyncio.Task[None] | None = None
76
78
  self.event_send_loop_task: asyncio.Task[None] | None = None
77
79
  self.running_step_runs: dict[str, float] = {}
80
+ self.step_action_events: set[
81
+ asyncio.Task[UnaryUnaryCall[StepActionEvent, ActionEventResponse] | None]
82
+ ] = set()
83
+ self.group_key_action_events: set[
84
+ asyncio.Task[
85
+ UnaryUnaryCall[GroupKeyActionEvent, ActionEventResponse] | None
86
+ ]
87
+ ] = set()
78
88
 
79
89
  if self.debug:
80
90
  logger.setLevel(logging.DEBUG)
@@ -144,20 +154,21 @@ class WorkerActionListenerProcess:
144
154
  break
145
155
 
146
156
  logger.debug(f"tx: event: {event.action.action_id}/{event.type}")
147
- asyncio.create_task(self.send_event(event))
157
+ t = asyncio.create_task(self.send_event(event))
158
+ self.step_action_events.add(t)
159
+ t.add_done_callback(lambda t: self.step_action_events.discard(t))
148
160
 
149
161
  async def start_blocked_main_loop(self) -> None:
150
162
  threshold = 1
151
163
  while not self.killing:
152
164
  count = 0
153
- for _, start_time in self.running_step_runs.items():
165
+ for start_time in self.running_step_runs.values():
154
166
  diff = self.now() - start_time
155
167
  if diff > threshold:
156
168
  count += 1
157
169
 
158
170
  if count > 0:
159
171
  logger.warning(f"{BLOCKED_THREAD_WARNING}: Waiting Steps {count}")
160
- print(asyncio.current_task())
161
172
  await asyncio.sleep(1)
162
173
 
163
174
  async def send_event(self, event: ActionEvent, retry_attempt: int = 1) -> None:
@@ -187,7 +198,7 @@ class WorkerActionListenerProcess:
187
198
  self.now()
188
199
  )
189
200
 
190
- asyncio.create_task(
201
+ send_started_event_task = asyncio.create_task(
191
202
  self.dispatcher_client.send_step_action_event(
192
203
  event.action,
193
204
  event.type,
@@ -195,14 +206,23 @@ class WorkerActionListenerProcess:
195
206
  event.should_not_retry,
196
207
  )
197
208
  )
209
+
210
+ self.step_action_events.add(send_started_event_task)
211
+ send_started_event_task.add_done_callback(
212
+ lambda t: self.step_action_events.discard(t)
213
+ )
198
214
  case ActionType.CANCEL_STEP_RUN:
199
215
  logger.debug("unimplemented event send")
200
216
  case ActionType.START_GET_GROUP_KEY:
201
- asyncio.create_task(
217
+ get_group_key_task = asyncio.create_task(
202
218
  self.dispatcher_client.send_group_key_action_event(
203
219
  event.action, event.type, event.payload
204
220
  )
205
221
  )
222
+ self.group_key_action_events.add(get_group_key_task)
223
+ get_group_key_task.add_done_callback(
224
+ lambda t: self.group_key_action_events.discard(t)
225
+ )
206
226
  case _:
207
227
  logger.error("unknown action type for event send")
208
228
  except Exception as e:
@@ -317,7 +337,7 @@ def worker_action_listener_process(*args: Any, **kwargs: Any) -> None:
317
337
  process = WorkerActionListenerProcess(*args, **kwargs)
318
338
  await process.start()
319
339
  # Keep the process running
320
- while not process.killing:
340
+ while not process.killing: # noqa: ASYNC110
321
341
  await asyncio.sleep(0.1)
322
342
 
323
343
  asyncio.run(run())
@@ -1,19 +1,17 @@
1
1
  import asyncio
2
2
  import logging
3
3
  from multiprocessing import Queue
4
- from typing import Any, Literal, TypeVar
4
+ from typing import Any, TypeVar
5
5
 
6
6
  from hatchet_sdk.client import Client
7
7
  from hatchet_sdk.config import ClientConfig
8
8
  from hatchet_sdk.logger import logger
9
9
  from hatchet_sdk.runnables.action import Action
10
10
  from hatchet_sdk.runnables.task import Task
11
+ from hatchet_sdk.utils.typing import STOP_LOOP, STOP_LOOP_TYPE
11
12
  from hatchet_sdk.worker.action_listener_process import ActionEvent
12
13
  from hatchet_sdk.worker.runner.runner import Runner
13
- from hatchet_sdk.worker.runner.utils.capture_logs import capture_logs
14
-
15
- STOP_LOOP_TYPE = Literal["STOP_LOOP"]
16
- STOP_LOOP: STOP_LOOP_TYPE = "STOP_LOOP"
14
+ from hatchet_sdk.worker.runner.utils.capture_logs import AsyncLogSender, capture_logs
17
15
 
18
16
  T = TypeVar("T")
19
17
 
@@ -28,10 +26,10 @@ class WorkerActionRunLoopManager:
28
26
  action_queue: "Queue[Action | STOP_LOOP_TYPE]",
29
27
  event_queue: "Queue[ActionEvent]",
30
28
  loop: asyncio.AbstractEventLoop,
31
- handle_kill: bool = True,
32
- debug: bool = False,
33
- labels: dict[str, str | int] = {},
34
- lifespan_context: Any | None = None,
29
+ handle_kill: bool,
30
+ debug: bool,
31
+ labels: dict[str, str | int] | None,
32
+ lifespan_context: Any | None,
35
33
  ) -> None:
36
34
  self.name = name
37
35
  self.action_registry = action_registry
@@ -52,15 +50,19 @@ class WorkerActionRunLoopManager:
52
50
  self.runner: Runner | None = None
53
51
 
54
52
  self.client = Client(config=self.config, debug=self.debug)
53
+ self.start_loop_manager_task: asyncio.Task[None] | None = None
54
+ self.log_sender = AsyncLogSender(self.client.event)
55
+ self.log_task = self.loop.create_task(self.log_sender.consume())
56
+
55
57
  self.start()
56
58
 
57
59
  def start(self) -> None:
58
- k = self.loop.create_task(self.aio_start()) # noqa: F841
60
+ self.start_loop_manager_task = self.loop.create_task(self.aio_start())
59
61
 
60
62
  async def aio_start(self, retry_count: int = 1) -> None:
61
63
  await capture_logs(
62
64
  self.client.log_interceptor,
63
- self.client.event,
65
+ self.log_sender,
64
66
  self._async_start,
65
67
  )()
66
68
 
@@ -75,6 +77,7 @@ class WorkerActionRunLoopManager:
75
77
  self.killing = True
76
78
 
77
79
  self.action_queue.put(STOP_LOOP)
80
+ self.log_sender.publish(STOP_LOOP)
78
81
 
79
82
  async def wait_for_tasks(self) -> None:
80
83
  if self.runner:
@@ -89,6 +92,7 @@ class WorkerActionRunLoopManager:
89
92
  self.action_registry,
90
93
  self.labels,
91
94
  self.lifespan_context,
95
+ self.log_sender,
92
96
  )
93
97
 
94
98
  logger.debug(f"'{self.name}' waiting for {list(self.action_registry.keys())}")