hatchet-sdk 1.10.0__py3-none-any.whl → 1.10.2__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
@@ -130,7 +130,7 @@ from hatchet_sdk.clients.rest.models.workflow_version_definition import (
130
130
  WorkflowVersionDefinition,
131
131
  )
132
132
  from hatchet_sdk.clients.rest.models.workflow_version_meta import WorkflowVersionMeta
133
- from hatchet_sdk.config import ClientConfig
133
+ from hatchet_sdk.config import ClientConfig, ClientTLSConfig, OpenTelemetryConfig
134
134
  from hatchet_sdk.context.context import Context, DurableContext
135
135
  from hatchet_sdk.context.worker_context import WorkerContext
136
136
  from hatchet_sdk.contracts.workflows_pb2 import (
@@ -149,6 +149,7 @@ from hatchet_sdk.runnables.types import (
149
149
  TaskDefaults,
150
150
  WorkflowConfig,
151
151
  )
152
+ from hatchet_sdk.utils.opentelemetry import OTelAttribute
152
153
  from hatchet_sdk.waits import (
153
154
  Condition,
154
155
  OrGroup,
@@ -271,4 +272,7 @@ __all__ = [
271
272
  "BulkCancelReplayOpts",
272
273
  "RunFilter",
273
274
  "V1TaskStatus",
275
+ "OTelAttribute",
276
+ "OpenTelemetryConfig",
277
+ "ClientTLSConfig",
274
278
  ]
@@ -20,6 +20,7 @@ from hatchet_sdk.features.runs import RunsClient
20
20
  from hatchet_sdk.metadata import get_metadata
21
21
  from hatchet_sdk.rate_limit import RateLimitDuration
22
22
  from hatchet_sdk.runnables.contextvars import (
23
+ ctx_action_key,
23
24
  ctx_step_run_id,
24
25
  ctx_worker_id,
25
26
  ctx_workflow_run_id,
@@ -281,11 +282,12 @@ class AdminClient:
281
282
  workflow_run_id = ctx_workflow_run_id.get()
282
283
  step_run_id = ctx_step_run_id.get()
283
284
  worker_id = ctx_worker_id.get()
284
- spawn_index = workflow_spawn_indices[workflow_run_id] if workflow_run_id else 0
285
+ action_key = ctx_action_key.get()
286
+ spawn_index = workflow_spawn_indices[action_key] if action_key else 0
285
287
 
286
288
  ## Increment the spawn_index for the parent workflow
287
- if workflow_run_id:
288
- workflow_spawn_indices[workflow_run_id] += 1
289
+ if action_key:
290
+ workflow_spawn_indices[action_key] += 1
289
291
 
290
292
  desired_worker_id = (
291
293
  (options.desired_worker_id or worker_id) if options.sticky else None
@@ -1,13 +1,11 @@
1
1
  import asyncio
2
2
  import json
3
3
  import time
4
- from dataclasses import field
5
- from enum import Enum
6
- from typing import Any, AsyncGenerator, cast
4
+ from typing import TYPE_CHECKING, AsyncGenerator, cast
7
5
 
8
6
  import grpc
9
7
  import grpc.aio
10
- from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
8
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
11
9
 
12
10
  from hatchet_sdk.clients.event_ts import (
13
11
  ThreadSafeEvent,
@@ -18,7 +16,6 @@ from hatchet_sdk.clients.events import proto_timestamp_now
18
16
  from hatchet_sdk.clients.listeners.run_event_listener import (
19
17
  DEFAULT_ACTION_LISTENER_RETRY_INTERVAL,
20
18
  )
21
- from hatchet_sdk.config import ClientConfig
22
19
  from hatchet_sdk.connection import new_conn
23
20
  from hatchet_sdk.contracts.dispatcher_pb2 import ActionType as ActionTypeProto
24
21
  from hatchet_sdk.contracts.dispatcher_pb2 import (
@@ -31,10 +28,15 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
31
28
  from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
32
29
  from hatchet_sdk.logger import logger
33
30
  from hatchet_sdk.metadata import get_metadata
31
+ from hatchet_sdk.runnables.action import Action, ActionPayload, ActionType
34
32
  from hatchet_sdk.utils.backoff import exp_backoff_sleep
35
33
  from hatchet_sdk.utils.proto_enums import convert_proto_enum_to_python
36
34
  from hatchet_sdk.utils.typing import JSONSerializableMapping
37
35
 
36
+ if TYPE_CHECKING:
37
+ from hatchet_sdk.config import ClientConfig
38
+
39
+
38
40
  DEFAULT_ACTION_TIMEOUT = 600 # seconds
39
41
  DEFAULT_ACTION_LISTENER_RETRY_COUNT = 15
40
42
 
@@ -63,117 +65,6 @@ class GetActionListenerRequest(BaseModel):
63
65
  return self
64
66
 
65
67
 
66
- class ActionPayload(BaseModel):
67
- model_config = ConfigDict(extra="allow")
68
-
69
- input: JSONSerializableMapping = Field(default_factory=dict)
70
- parents: dict[str, JSONSerializableMapping] = Field(default_factory=dict)
71
- overrides: JSONSerializableMapping = Field(default_factory=dict)
72
- user_data: JSONSerializableMapping = Field(default_factory=dict)
73
- step_run_errors: dict[str, str] = Field(default_factory=dict)
74
- triggered_by: str | None = None
75
- triggers: JSONSerializableMapping = Field(default_factory=dict)
76
- filter_payload: JSONSerializableMapping = Field(default_factory=dict)
77
-
78
- @field_validator(
79
- "input",
80
- "parents",
81
- "overrides",
82
- "user_data",
83
- "step_run_errors",
84
- "filter_payload",
85
- mode="before",
86
- )
87
- @classmethod
88
- def validate_fields(cls, v: Any) -> Any:
89
- return v or {}
90
-
91
- @model_validator(mode="after")
92
- def validate_filter_payload(self) -> "ActionPayload":
93
- self.filter_payload = self.triggers.get("filter_payload", {})
94
-
95
- return self
96
-
97
-
98
- class ActionType(str, Enum):
99
- START_STEP_RUN = "START_STEP_RUN"
100
- CANCEL_STEP_RUN = "CANCEL_STEP_RUN"
101
- START_GET_GROUP_KEY = "START_GET_GROUP_KEY"
102
-
103
-
104
- ActionKey = str
105
-
106
-
107
- class Action(BaseModel):
108
- worker_id: str
109
- tenant_id: str
110
- workflow_run_id: str
111
- workflow_id: str | None = None
112
- workflow_version_id: str | None = None
113
- get_group_key_run_id: str
114
- job_id: str
115
- job_name: str
116
- job_run_id: str
117
- step_id: str
118
- step_run_id: str
119
- action_id: str
120
- action_type: ActionType
121
- retry_count: int
122
- action_payload: ActionPayload
123
- additional_metadata: JSONSerializableMapping = field(default_factory=dict)
124
-
125
- child_workflow_index: int | None = None
126
- child_workflow_key: str | None = None
127
- parent_workflow_run_id: str | None = None
128
-
129
- priority: int | None = None
130
-
131
- def _dump_payload_to_str(self) -> str:
132
- try:
133
- return json.dumps(self.action_payload.model_dump(), default=str)
134
- except Exception:
135
- return str(self.action_payload)
136
-
137
- @property
138
- def otel_attributes(self) -> dict[str, str | int]:
139
- try:
140
- payload_str = json.dumps(self.action_payload.model_dump(), default=str)
141
- except Exception:
142
- payload_str = str(self.action_payload)
143
-
144
- attrs: dict[str, str | int | None] = {
145
- "hatchet.tenant_id": self.tenant_id,
146
- "hatchet.worker_id": self.worker_id,
147
- "hatchet.workflow_run_id": self.workflow_run_id,
148
- "hatchet.step_id": self.step_id,
149
- "hatchet.step_run_id": self.step_run_id,
150
- "hatchet.retry_count": self.retry_count,
151
- "hatchet.parent_workflow_run_id": self.parent_workflow_run_id,
152
- "hatchet.child_workflow_index": self.child_workflow_index,
153
- "hatchet.child_workflow_key": self.child_workflow_key,
154
- "hatchet.action_payload": payload_str,
155
- "hatchet.workflow_name": self.job_name,
156
- "hatchet.action_name": self.action_id,
157
- "hatchet.get_group_key_run_id": self.get_group_key_run_id,
158
- "hatchet.workflow_id": self.workflow_id,
159
- "hatchet.workflow_version_id": self.workflow_version_id,
160
- }
161
-
162
- return {k: v for k, v in attrs.items() if v}
163
-
164
- @property
165
- def key(self) -> ActionKey:
166
- """
167
- This key is used to uniquely identify a single step run by its id + retry count.
168
- It's used when storing references to a task, a context, etc. in a dictionary so that
169
- we can look up those items in the dictionary by a unique key.
170
- """
171
- if self.action_type == ActionType.START_GET_GROUP_KEY:
172
- return f"{self.get_group_key_run_id}/{self.retry_count}"
173
- else:
174
- return f"{self.step_run_id}/{self.retry_count}"
175
-
176
-
177
68
  def parse_additional_metadata(additional_metadata: str) -> JSONSerializableMapping:
178
69
  try:
179
70
  return cast(
@@ -185,7 +76,7 @@ def parse_additional_metadata(additional_metadata: str) -> JSONSerializableMappi
185
76
 
186
77
 
187
78
  class ActionListener:
188
- def __init__(self, config: ClientConfig, worker_id: str) -> None:
79
+ def __init__(self, config: "ClientConfig", worker_id: str) -> None:
189
80
  self.config = config
190
81
  self.worker_id = worker_id
191
82
 
@@ -4,7 +4,6 @@ import grpc.aio
4
4
  from google.protobuf.timestamp_pb2 import Timestamp
5
5
 
6
6
  from hatchet_sdk.clients.dispatcher.action_listener import (
7
- Action,
8
7
  ActionListener,
9
8
  GetActionListenerRequest,
10
9
  )
@@ -29,6 +28,7 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
29
28
  )
30
29
  from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
31
30
  from hatchet_sdk.metadata import get_metadata
31
+ from hatchet_sdk.runnables.action import Action
32
32
 
33
33
  DEFAULT_REGISTER_TIMEOUT = 30
34
34
 
hatchet_sdk/config.py CHANGED
@@ -6,6 +6,7 @@ from pydantic import Field, field_validator, model_validator
6
6
  from pydantic_settings import BaseSettings, SettingsConfigDict
7
7
 
8
8
  from hatchet_sdk.token import get_addresses_from_jwt, get_tenant_id_from_jwt
9
+ from hatchet_sdk.utils.opentelemetry import OTelAttribute
9
10
 
10
11
 
11
12
  def create_settings_config(env_prefix: str) -> SettingsConfigDict:
@@ -37,6 +38,17 @@ class HealthcheckConfig(BaseSettings):
37
38
  enabled: bool = False
38
39
 
39
40
 
41
+ class OpenTelemetryConfig(BaseSettings):
42
+ model_config = create_settings_config(
43
+ env_prefix="HATCHET_CLIENT_OPENTELEMETRY_",
44
+ )
45
+
46
+ excluded_attributes: list[OTelAttribute] = Field(
47
+ default_factory=list,
48
+ description='Note that if specifying this field via an environment variable, the variable must be a valid JSON array. For example: \'["action_name", "action_payload"]\'',
49
+ )
50
+
51
+
40
52
  DEFAULT_HOST_PORT = "localhost:7070"
41
53
 
42
54
 
@@ -55,6 +67,7 @@ class ClientConfig(BaseSettings):
55
67
 
56
68
  tls_config: ClientTLSConfig = Field(default_factory=lambda: ClientTLSConfig())
57
69
  healthcheck: HealthcheckConfig = Field(default_factory=lambda: HealthcheckConfig())
70
+ otel: OpenTelemetryConfig = Field(default_factory=lambda: OpenTelemetryConfig())
58
71
 
59
72
  listener_v2_timeout: int | None = None
60
73
  grpc_max_recv_message_length: int = Field(
@@ -27,18 +27,19 @@ except (RuntimeError, ImportError, ModuleNotFoundError):
27
27
  )
28
28
 
29
29
  import hatchet_sdk
30
+ from hatchet_sdk import ClientConfig
30
31
  from hatchet_sdk.clients.admin import (
31
32
  AdminClient,
32
33
  TriggerWorkflowOptions,
33
34
  WorkflowRunTriggerConfig,
34
35
  )
35
- from hatchet_sdk.clients.dispatcher.action_listener import Action
36
36
  from hatchet_sdk.clients.events import (
37
37
  BulkPushEventWithMetadata,
38
38
  EventClient,
39
39
  PushEventOptions,
40
40
  )
41
41
  from hatchet_sdk.contracts.events_pb2 import Event
42
+ from hatchet_sdk.runnables.action import Action
42
43
  from hatchet_sdk.worker.runner.runner import Runner
43
44
  from hatchet_sdk.workflow_run import WorkflowRunRef
44
45
 
@@ -148,13 +149,17 @@ class HatchetInstrumentor(BaseInstrumentor): # type: ignore[misc]
148
149
  If not provided, the global tracer provider will be used.
149
150
  :param meter_provider: MeterProvider | None: The OpenTelemetry MeterProvider to use.
150
151
  If not provided, a no-op meter provider will be used.
152
+ :param config: ClientConfig | None: The configuration for the Hatchet client. If not provided,
153
+ a default configuration will be used.
151
154
  """
152
155
 
153
156
  def __init__(
154
157
  self,
155
158
  tracer_provider: TracerProvider | None = None,
156
159
  meter_provider: MeterProvider | None = None,
160
+ config: ClientConfig | None = None,
157
161
  ):
162
+ self.config = config or ClientConfig()
158
163
 
159
164
  self.tracer_provider = tracer_provider or get_tracer_provider()
160
165
  self.meter_provider = meter_provider or NoOpMeterProvider()
@@ -233,7 +238,7 @@ class HatchetInstrumentor(BaseInstrumentor): # type: ignore[misc]
233
238
 
234
239
  with self._tracer.start_as_current_span(
235
240
  "hatchet.start_step_run",
236
- attributes=action.otel_attributes,
241
+ attributes=action.get_otel_attributes(self.config),
237
242
  context=traceparent,
238
243
  ) as span:
239
244
  result = await wrapped(*args, **kwargs)
@@ -255,7 +260,7 @@ class HatchetInstrumentor(BaseInstrumentor): # type: ignore[misc]
255
260
 
256
261
  with self._tracer.start_as_current_span(
257
262
  "hatchet.get_group_key_run",
258
- attributes=action.otel_attributes,
263
+ attributes=action.get_otel_attributes(self.config),
259
264
  ) as span:
260
265
  result = await wrapped(*args, **kwargs)
261
266
 
@@ -0,0 +1,125 @@
1
+ import json
2
+ from dataclasses import field
3
+ from enum import Enum
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
7
+
8
+ from hatchet_sdk.utils.opentelemetry import OTelAttribute
9
+ from hatchet_sdk.utils.typing import JSONSerializableMapping
10
+
11
+ if TYPE_CHECKING:
12
+ from hatchet_sdk.config import ClientConfig
13
+
14
+ ActionKey = str
15
+
16
+
17
+ class ActionPayload(BaseModel):
18
+ model_config = ConfigDict(extra="allow")
19
+
20
+ input: JSONSerializableMapping = Field(default_factory=dict)
21
+ parents: dict[str, JSONSerializableMapping] = Field(default_factory=dict)
22
+ overrides: JSONSerializableMapping = Field(default_factory=dict)
23
+ user_data: JSONSerializableMapping = Field(default_factory=dict)
24
+ step_run_errors: dict[str, str] = Field(default_factory=dict)
25
+ triggered_by: str | None = None
26
+ triggers: JSONSerializableMapping = Field(default_factory=dict)
27
+ filter_payload: JSONSerializableMapping = Field(default_factory=dict)
28
+
29
+ @field_validator(
30
+ "input",
31
+ "parents",
32
+ "overrides",
33
+ "user_data",
34
+ "step_run_errors",
35
+ "filter_payload",
36
+ mode="before",
37
+ )
38
+ @classmethod
39
+ def validate_fields(cls, v: Any) -> Any:
40
+ return v or {}
41
+
42
+ @model_validator(mode="after")
43
+ def validate_filter_payload(self) -> "ActionPayload":
44
+ self.filter_payload = self.triggers.get("filter_payload", {})
45
+
46
+ return self
47
+
48
+
49
+ class ActionType(str, Enum):
50
+ START_STEP_RUN = "START_STEP_RUN"
51
+ CANCEL_STEP_RUN = "CANCEL_STEP_RUN"
52
+ START_GET_GROUP_KEY = "START_GET_GROUP_KEY"
53
+
54
+
55
+ class Action(BaseModel):
56
+ worker_id: str
57
+ tenant_id: str
58
+ workflow_run_id: str
59
+ workflow_id: str | None = None
60
+ workflow_version_id: str | None = None
61
+ get_group_key_run_id: str
62
+ job_id: str
63
+ job_name: str
64
+ job_run_id: str
65
+ step_id: str
66
+ step_run_id: str
67
+ action_id: str
68
+ action_type: ActionType
69
+ retry_count: int
70
+ action_payload: ActionPayload
71
+ additional_metadata: JSONSerializableMapping = field(default_factory=dict)
72
+
73
+ child_workflow_index: int | None = None
74
+ child_workflow_key: str | None = None
75
+ parent_workflow_run_id: str | None = None
76
+
77
+ priority: int | None = None
78
+
79
+ def _dump_payload_to_str(self) -> str:
80
+ try:
81
+ return json.dumps(self.action_payload.model_dump(), default=str)
82
+ except Exception:
83
+ return str(self.action_payload)
84
+
85
+ def get_otel_attributes(self, config: "ClientConfig") -> dict[str, str | int]:
86
+ try:
87
+ payload_str = json.dumps(self.action_payload.model_dump(), default=str)
88
+ except Exception:
89
+ payload_str = str(self.action_payload)
90
+
91
+ attrs: dict[OTelAttribute, str | int | None] = {
92
+ OTelAttribute.TENANT_ID: self.tenant_id,
93
+ OTelAttribute.WORKER_ID: self.worker_id,
94
+ OTelAttribute.WORKFLOW_RUN_ID: self.workflow_run_id,
95
+ OTelAttribute.STEP_ID: self.step_id,
96
+ OTelAttribute.STEP_RUN_ID: self.step_run_id,
97
+ OTelAttribute.RETRY_COUNT: self.retry_count,
98
+ OTelAttribute.PARENT_WORKFLOW_RUN_ID: self.parent_workflow_run_id,
99
+ OTelAttribute.CHILD_WORKFLOW_INDEX: self.child_workflow_index,
100
+ OTelAttribute.CHILD_WORKFLOW_KEY: self.child_workflow_key,
101
+ OTelAttribute.ACTION_PAYLOAD: payload_str,
102
+ OTelAttribute.WORKFLOW_NAME: self.job_name,
103
+ OTelAttribute.ACTION_NAME: self.action_id,
104
+ OTelAttribute.GET_GROUP_KEY_RUN_ID: self.get_group_key_run_id,
105
+ OTelAttribute.WORKFLOW_ID: self.workflow_id,
106
+ OTelAttribute.WORKFLOW_VERSION_ID: self.workflow_version_id,
107
+ }
108
+
109
+ return {
110
+ f"hatchet.{k.value}": v
111
+ for k, v in attrs.items()
112
+ if v and k not in config.otel.excluded_attributes
113
+ }
114
+
115
+ @property
116
+ def key(self) -> ActionKey:
117
+ """
118
+ This key is used to uniquely identify a single step run by its id + retry count.
119
+ It's used when storing references to a task, a context, etc. in a dictionary so that
120
+ we can look up those items in the dictionary by a unique key.
121
+ """
122
+ if self.action_type == ActionType.START_GET_GROUP_KEY:
123
+ return f"{self.get_group_key_run_id}/{self.retry_count}"
124
+ else:
125
+ return f"{self.step_run_id}/{self.retry_count}"
@@ -2,11 +2,16 @@ import asyncio
2
2
  from collections import Counter
3
3
  from contextvars import ContextVar
4
4
 
5
+ from hatchet_sdk.runnables.action import ActionKey
6
+
5
7
  ctx_workflow_run_id: ContextVar[str | None] = ContextVar(
6
8
  "ctx_workflow_run_id", default=None
7
9
  )
10
+ ctx_action_key: ContextVar[ActionKey | None] = ContextVar(
11
+ "ctx_action_key", default=None
12
+ )
8
13
  ctx_step_run_id: ContextVar[str | None] = ContextVar("ctx_step_run_id", default=None)
9
14
  ctx_worker_id: ContextVar[str | None] = ContextVar("ctx_worker_id", default=None)
10
15
 
11
- workflow_spawn_indices = Counter[str]()
16
+ workflow_spawn_indices = Counter[ActionKey]()
12
17
  spawn_index_lock = asyncio.Lock()
@@ -0,0 +1,19 @@
1
+ from enum import Enum
2
+
3
+
4
+ class OTelAttribute(str, Enum):
5
+ ACTION_NAME = "action_name"
6
+ ACTION_PAYLOAD = "action_payload"
7
+ CHILD_WORKFLOW_INDEX = "child_workflow_index"
8
+ CHILD_WORKFLOW_KEY = "child_workflow_key"
9
+ GET_GROUP_KEY_RUN_ID = "get_group_key_run_id"
10
+ PARENT_WORKFLOW_RUN_ID = "parent_workflow_run_id"
11
+ RETRY_COUNT = "retry_count"
12
+ STEP_ID = "step_id"
13
+ STEP_RUN_ID = "step_run_id"
14
+ TENANT_ID = "tenant_id"
15
+ WORKER_ID = "worker_id"
16
+ WORKFLOW_ID = "workflow_id"
17
+ WORKFLOW_NAME = "workflow_name"
18
+ WORKFLOW_RUN_ID = "workflow_run_id"
19
+ WORKFLOW_VERSION_ID = "workflow_version_id"
@@ -10,9 +10,7 @@ import grpc
10
10
 
11
11
  from hatchet_sdk.client import Client
12
12
  from hatchet_sdk.clients.dispatcher.action_listener import (
13
- Action,
14
13
  ActionListener,
15
- ActionType,
16
14
  GetActionListenerRequest,
17
15
  )
18
16
  from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
@@ -23,7 +21,9 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
23
21
  STEP_EVENT_TYPE_STARTED,
24
22
  )
25
23
  from hatchet_sdk.logger import logger
24
+ from hatchet_sdk.runnables.action import Action, ActionType
26
25
  from hatchet_sdk.runnables.contextvars import (
26
+ ctx_action_key,
27
27
  ctx_step_run_id,
28
28
  ctx_worker_id,
29
29
  ctx_workflow_run_id,
@@ -230,6 +230,7 @@ class WorkerActionListenerProcess:
230
230
  ctx_step_run_id.set(action.step_run_id)
231
231
  ctx_workflow_run_id.set(action.workflow_run_id)
232
232
  ctx_worker_id.set(action.worker_id)
233
+ ctx_action_key.set(action.key)
233
234
 
234
235
  # Process the action here
235
236
  match action.action_type:
@@ -4,9 +4,9 @@ from multiprocessing import Queue
4
4
  from typing import Any, Literal, TypeVar
5
5
 
6
6
  from hatchet_sdk.client import Client
7
- from hatchet_sdk.clients.dispatcher.action_listener import Action
8
7
  from hatchet_sdk.config import ClientConfig
9
8
  from hatchet_sdk.logger import logger
9
+ from hatchet_sdk.runnables.action import Action
10
10
  from hatchet_sdk.runnables.task import Task
11
11
  from hatchet_sdk.worker.action_listener_process import ActionEvent
12
12
  from hatchet_sdk.worker.runner.runner import Runner
@@ -14,7 +14,6 @@ from pydantic import BaseModel
14
14
 
15
15
  from hatchet_sdk.client import Client
16
16
  from hatchet_sdk.clients.admin import AdminClient
17
- from hatchet_sdk.clients.dispatcher.action_listener import Action, ActionKey, ActionType
18
17
  from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
19
18
  from hatchet_sdk.clients.events import EventClient
20
19
  from hatchet_sdk.clients.listeners.durable_event_listener import DurableEventListener
@@ -34,7 +33,9 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
34
33
  from hatchet_sdk.exceptions import NonRetryableException
35
34
  from hatchet_sdk.features.runs import RunsClient
36
35
  from hatchet_sdk.logger import logger
36
+ from hatchet_sdk.runnables.action import Action, ActionKey, ActionType
37
37
  from hatchet_sdk.runnables.contextvars import (
38
+ ctx_action_key,
38
39
  ctx_step_run_id,
39
40
  ctx_worker_id,
40
41
  ctx_workflow_run_id,
@@ -244,6 +245,7 @@ class Runner:
244
245
  ctx_step_run_id.set(action.step_run_id)
245
246
  ctx_workflow_run_id.set(action.workflow_run_id)
246
247
  ctx_worker_id.set(action.worker_id)
248
+ ctx_action_key.set(action.key)
247
249
 
248
250
  try:
249
251
  if task.is_async_function:
@@ -388,9 +390,9 @@ class Runner:
388
390
 
389
391
  ## Once the step run completes, we need to remove the workflow spawn index
390
392
  ## so we don't leak memory
391
- if action.workflow_run_id in workflow_spawn_indices:
393
+ if action.key in workflow_spawn_indices:
392
394
  async with spawn_index_lock:
393
- workflow_spawn_indices.pop(action.workflow_run_id)
395
+ workflow_spawn_indices.pop(action.key)
394
396
 
395
397
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
396
398
  async def handle_start_group_key_run(self, action: Action) -> Exception | None:
@@ -21,10 +21,10 @@ from prometheus_client import Gauge, generate_latest
21
21
  from pydantic import BaseModel
22
22
 
23
23
  from hatchet_sdk.client import Client
24
- from hatchet_sdk.clients.dispatcher.action_listener import Action
25
24
  from hatchet_sdk.config import ClientConfig
26
25
  from hatchet_sdk.contracts.v1.workflows_pb2 import CreateWorkflowVersionRequest
27
26
  from hatchet_sdk.logger import logger
27
+ from hatchet_sdk.runnables.action import Action
28
28
  from hatchet_sdk.runnables.task import Task
29
29
  from hatchet_sdk.runnables.workflow import BaseWorkflow
30
30
  from hatchet_sdk.worker.action_listener_process import (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hatchet-sdk
3
- Version: 1.10.0
3
+ Version: 1.10.2
4
4
  Summary:
5
5
  License: MIT
6
6
  Author: Alexander Belanger
@@ -1,8 +1,8 @@
1
- hatchet_sdk/__init__.py,sha256=LUj6VyGVSHCYTQTaoyiVhjyJLOfv6gMCmb-s4hRyISM,10031
1
+ hatchet_sdk/__init__.py,sha256=TW5T_It9W79Lfu-QaxMYBXMjYaXQdOpOS6bvYJm6VjQ,10198
2
2
  hatchet_sdk/client.py,sha256=7ONBiE29OKQci3Qaz7U5e-WSxO_ohnWq8F-MSgzG2fU,2312
3
- hatchet_sdk/clients/admin.py,sha256=zV0Tehvq8m-QNdvB_9VHO38nnOtIhKMbQzsgp_E2KU4,16887
4
- hatchet_sdk/clients/dispatcher/action_listener.py,sha256=Kd_PxQlYDa456KlF66Y8SdJXhcpywSWtyP6rppH_TfM,17624
5
- hatchet_sdk/clients/dispatcher/dispatcher.py,sha256=IL-hDXG8Lzas9FieVuNr47E_3Gvpc-aL4Xu_l385Vp8,8140
3
+ hatchet_sdk/clients/admin.py,sha256=7Nxtn1KemJTjWs0yEaU7OyXIFQNFUF3NzLd2E_kJmMQ,16929
4
+ hatchet_sdk/clients/dispatcher/action_listener.py,sha256=XUDXye-HW4V30DBgjd_dmq7e03AS9eBxUJi1VsvfSqE,13837
5
+ hatchet_sdk/clients/dispatcher/dispatcher.py,sha256=LoxQEX5FS6v-qKRtOXoqsx3VlBUgFgTkbK58LU1eU3I,8176
6
6
  hatchet_sdk/clients/event_ts.py,sha256=MudFszIb9IcPKQYvBTzcatPkcWEy3nxbAtEQ0_NYxMg,2094
7
7
  hatchet_sdk/clients/events.py,sha256=6nfZogeEgXC0Tzq6RDCTVPcBvLBVBlEonlTo-ticfrc,7200
8
8
  hatchet_sdk/clients/listeners/durable_event_listener.py,sha256=jpqnbZsuouWk3XaOIYL9apaGtVk65eKKq66eBP9klBs,4085
@@ -227,7 +227,7 @@ hatchet_sdk/clients/rest/models/workflow_workers_count.py,sha256=qhzqfvjjIDyARki
227
227
  hatchet_sdk/clients/rest/rest.py,sha256=zZHTzgl-NBdcK6XhG23m_s9RKRONGPPItzGe407s7GA,9262
228
228
  hatchet_sdk/clients/rest/tenacity_utils.py,sha256=n6QvwuGwinLQpiWNU5GxrDNhFBE8_wZdg3WNur21rJ0,1055
229
229
  hatchet_sdk/clients/v1/api_client.py,sha256=mJQUZ3cOxlFJiwWKK5F8jBxcpNZ7A2292HucrBqurbg,1205
230
- hatchet_sdk/config.py,sha256=Vntn5N8xXqbigr93oyuecZhKwt_n5zafnDw1COAs7AI,4571
230
+ hatchet_sdk/config.py,sha256=iQFnT8teWiov0c2l1BzByBuzn2fgKOxvMt5Yt33oLsE,5128
231
231
  hatchet_sdk/connection.py,sha256=B5gT5NL9BBB5-l9U_cN6pMlraQk880rEYMnqaK_dgL0,2590
232
232
  hatchet_sdk/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
233
  hatchet_sdk/context/context.py,sha256=ue6ewQZ_y2k2DQ5fVvCrArV7sI-Q7fpehCkadZvi1vg,9334
@@ -264,16 +264,18 @@ hatchet_sdk/hatchet.py,sha256=BVWSrKL6GCzarTNAte_r0iWsaBXntxNzrR-syR6qENI,22885
264
264
  hatchet_sdk/labels.py,sha256=nATgxWE3lFxRTnfISEpoIRLGbMfAZsHF4lZTuG4Mfic,182
265
265
  hatchet_sdk/logger.py,sha256=5uOr52T4mImSQm1QvWT8HvZFK5WfPNh3Y1cBQZRFgUQ,333
266
266
  hatchet_sdk/metadata.py,sha256=XkRbhnghJJGCdVvF-uzyGBcNaTqpeQ3uiQvNNP1wyBc,107
267
- hatchet_sdk/opentelemetry/instrumentor.py,sha256=GbsMZ1c9s0VRE7wwq-Iz5U9sT9fl7ZdXJ_ddqOqO5B0,13815
267
+ hatchet_sdk/opentelemetry/instrumentor.py,sha256=TMv2cks2O6026dZ0FGLcMGswCcKNjAFv4dSkRCnqxIw,14108
268
268
  hatchet_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
269
269
  hatchet_sdk/rate_limit.py,sha256=TwbCuggiZaWpYuo4mjVLlE-z1OfQ2mRBiVvCSaG3lv4,3919
270
- hatchet_sdk/runnables/contextvars.py,sha256=6MDocAMmlyiRW37oQ1jyx10tAlJs-xgDjR3xPoPz05g,426
270
+ hatchet_sdk/runnables/action.py,sha256=-CJ1b0SnLdXvWH9HZhhoAmKO68WJRGRn7Y7vcLNr1NU,4396
271
+ hatchet_sdk/runnables/contextvars.py,sha256=3hXlW03FNg2sEq8_A7wMPf_c7FTNuZqg5U9n2S2_hgg,580
271
272
  hatchet_sdk/runnables/standalone.py,sha256=5MKyLIScJbTHc6N3lRJc6L2Y_9SZj_dQWLV9oA46kqk,15663
272
273
  hatchet_sdk/runnables/task.py,sha256=AOpULMr3hqxn4W58Lh9oEvsXn_7PPB_c_sIqHRfQn5Q,7063
273
274
  hatchet_sdk/runnables/types.py,sha256=5jf1c7_0QVUFh0bcXi4hIiaOdUiyhspU4LltoAFCwlM,3776
274
275
  hatchet_sdk/runnables/workflow.py,sha256=lgN2z9or8E4jgHf6C31Kf1KsTa8_rEtE0AwIqGpNEH8,39926
275
276
  hatchet_sdk/token.py,sha256=KjIiInwG5Kqd_FO4BSW1x_5Uc7PFbnzIVJqr50-ZldE,779
276
277
  hatchet_sdk/utils/backoff.py,sha256=6B5Rb5nLKw_TqqgpJMYjIBV1PTTtbOMRZCveisVhg_I,353
278
+ hatchet_sdk/utils/opentelemetry.py,sha256=EadD6jy6J_kTBqDukH5ufg7kJA_VF8LLKUd-NpSZoD8,626
277
279
  hatchet_sdk/utils/proto_enums.py,sha256=0UybwE3s7TcqmzoQSO8YnhgAKOS8WZXsyPchB8-eksw,1247
278
280
  hatchet_sdk/utils/timedelta_to_expression.py,sha256=kwuYZ51JdDdc3h9Sw4vgBFmJBMPkgbGJA4v9uO4_NGk,660
279
281
  hatchet_sdk/utils/typing.py,sha256=P6-Nd5K_Hk-VhEkGj6LYki_9ddw05rJtzRA56qGXHag,914
@@ -510,13 +512,13 @@ hatchet_sdk/v0/workflow.py,sha256=d4o425efk7J3JgLIge34MW_A3pzwnwSRtwEOgIqM2pc,93
510
512
  hatchet_sdk/v0/workflow_run.py,sha256=jsEZprXshrSV7i_TtL5uoCL03D18zQ3NeJCq7mp97Dg,1752
511
513
  hatchet_sdk/waits.py,sha256=L2xZUcmrQX-pTVXWv1W8suMoYU_eA0uowpollauQmOM,3893
512
514
  hatchet_sdk/worker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
513
- hatchet_sdk/worker/action_listener_process.py,sha256=t6COI8KmYoYooFLMZY5KLNPQmJrIrs4luoVZxPnKN_I,11775
514
- hatchet_sdk/worker/runner/run_loop_manager.py,sha256=RNWKDCjR57nJ0LCoLUMi0_3pnmpqyo80mz_RaxHYGIc,3812
515
- hatchet_sdk/worker/runner/runner.py,sha256=CdsWl0l4tFp8Yy35uLsR74jNsBs-fIHiDAJZwPSGrKg,18805
515
+ hatchet_sdk/worker/action_listener_process.py,sha256=6WLtKLn8dRikzHLWwkHkoMuEf18WTKbxwNoT5WlPOBk,11874
516
+ hatchet_sdk/worker/runner/run_loop_manager.py,sha256=E3KD1r0-BBKUWlZJMDo9e2HHl4uAyvL8gX42-JCRLLc,3794
517
+ hatchet_sdk/worker/runner/runner.py,sha256=9Z3Ac6hRh5rjet7-BRtpcFARlhWvy6TNrdsdj61k_yk,18822
516
518
  hatchet_sdk/worker/runner/utils/capture_logs.py,sha256=nHRPSiDBqzhObM7i2X7t03OupVFnE7kQBdR2Ckgg-2w,2709
517
- hatchet_sdk/worker/worker.py,sha256=tFXqyPFR4Cplb4zcuzEpZq0VXLtTJrYh7WB0wNC2lTQ,16106
519
+ hatchet_sdk/worker/worker.py,sha256=SAucu3dg8lkKLbzb3noNWvClZ09lC5tuRcBkYZtIJ-0,16088
518
520
  hatchet_sdk/workflow_run.py,sha256=ZwH0HLFGFVXz6jbiqSv4w0Om2XuR52Tzzw6LH4y65jQ,2765
519
- hatchet_sdk-1.10.0.dist-info/METADATA,sha256=sutWBTdej3ThPn40hhRT0RSz3DZkJgRs3D4sQdUraRk,3636
520
- hatchet_sdk-1.10.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
521
- hatchet_sdk-1.10.0.dist-info/entry_points.txt,sha256=Un_76pcLse-ZGBlwebhQpnTPyQrripeHW8J7qmEpGOk,1400
522
- hatchet_sdk-1.10.0.dist-info/RECORD,,
521
+ hatchet_sdk-1.10.2.dist-info/METADATA,sha256=GDuCe5FAd2VC2rWKjkVr-QZbk9LSByY0r8YuQ13E1l8,3636
522
+ hatchet_sdk-1.10.2.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
523
+ hatchet_sdk-1.10.2.dist-info/entry_points.txt,sha256=Un_76pcLse-ZGBlwebhQpnTPyQrripeHW8J7qmEpGOk,1400
524
+ hatchet_sdk-1.10.2.dist-info/RECORD,,