hatchet-sdk 1.18.1__py3-none-any.whl → 1.20.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 (234) hide show
  1. hatchet_sdk/clients/dispatcher/action_listener.py +0 -1
  2. hatchet_sdk/clients/dispatcher/dispatcher.py +0 -30
  3. hatchet_sdk/hatchet.py +0 -20
  4. hatchet_sdk/opentelemetry/instrumentor.py +1 -27
  5. hatchet_sdk/runnables/action.py +2 -5
  6. hatchet_sdk/runnables/task.py +0 -1
  7. hatchet_sdk/utils/opentelemetry.py +0 -1
  8. hatchet_sdk/worker/action_listener_process.py +0 -29
  9. hatchet_sdk/worker/runner/runner.py +1 -105
  10. {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/METADATA +2 -3
  11. {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/RECORD +13 -234
  12. hatchet_sdk/v0/__init__.py +0 -251
  13. hatchet_sdk/v0/client.py +0 -119
  14. hatchet_sdk/v0/clients/admin.py +0 -541
  15. hatchet_sdk/v0/clients/dispatcher/action_listener.py +0 -422
  16. hatchet_sdk/v0/clients/dispatcher/dispatcher.py +0 -204
  17. hatchet_sdk/v0/clients/event_ts.py +0 -28
  18. hatchet_sdk/v0/clients/events.py +0 -182
  19. hatchet_sdk/v0/clients/rest/__init__.py +0 -307
  20. hatchet_sdk/v0/clients/rest/api/__init__.py +0 -19
  21. hatchet_sdk/v0/clients/rest/api/api_token_api.py +0 -858
  22. hatchet_sdk/v0/clients/rest/api/default_api.py +0 -2259
  23. hatchet_sdk/v0/clients/rest/api/event_api.py +0 -2548
  24. hatchet_sdk/v0/clients/rest/api/github_api.py +0 -331
  25. hatchet_sdk/v0/clients/rest/api/healthcheck_api.py +0 -483
  26. hatchet_sdk/v0/clients/rest/api/log_api.py +0 -449
  27. hatchet_sdk/v0/clients/rest/api/metadata_api.py +0 -728
  28. hatchet_sdk/v0/clients/rest/api/rate_limits_api.py +0 -423
  29. hatchet_sdk/v0/clients/rest/api/slack_api.py +0 -577
  30. hatchet_sdk/v0/clients/rest/api/sns_api.py +0 -872
  31. hatchet_sdk/v0/clients/rest/api/step_run_api.py +0 -2202
  32. hatchet_sdk/v0/clients/rest/api/tenant_api.py +0 -4430
  33. hatchet_sdk/v0/clients/rest/api/user_api.py +0 -2888
  34. hatchet_sdk/v0/clients/rest/api/worker_api.py +0 -858
  35. hatchet_sdk/v0/clients/rest/api/workflow_api.py +0 -6312
  36. hatchet_sdk/v0/clients/rest/api/workflow_run_api.py +0 -1932
  37. hatchet_sdk/v0/clients/rest/api/workflow_runs_api.py +0 -610
  38. hatchet_sdk/v0/clients/rest/api_client.py +0 -759
  39. hatchet_sdk/v0/clients/rest/api_response.py +0 -22
  40. hatchet_sdk/v0/clients/rest/configuration.py +0 -611
  41. hatchet_sdk/v0/clients/rest/exceptions.py +0 -200
  42. hatchet_sdk/v0/clients/rest/models/__init__.py +0 -274
  43. hatchet_sdk/v0/clients/rest/models/accept_invite_request.py +0 -83
  44. hatchet_sdk/v0/clients/rest/models/api_error.py +0 -102
  45. hatchet_sdk/v0/clients/rest/models/api_errors.py +0 -100
  46. hatchet_sdk/v0/clients/rest/models/api_meta.py +0 -144
  47. hatchet_sdk/v0/clients/rest/models/api_meta_auth.py +0 -85
  48. hatchet_sdk/v0/clients/rest/models/api_meta_integration.py +0 -88
  49. hatchet_sdk/v0/clients/rest/models/api_meta_posthog.py +0 -90
  50. hatchet_sdk/v0/clients/rest/models/api_resource_meta.py +0 -98
  51. hatchet_sdk/v0/clients/rest/models/api_token.py +0 -105
  52. hatchet_sdk/v0/clients/rest/models/bulk_create_event_request.py +0 -100
  53. hatchet_sdk/v0/clients/rest/models/bulk_create_event_response.py +0 -110
  54. hatchet_sdk/v0/clients/rest/models/cancel_event_request.py +0 -85
  55. hatchet_sdk/v0/clients/rest/models/cancel_step_run_request.py +0 -83
  56. hatchet_sdk/v0/clients/rest/models/concurrency_limit_strategy.py +0 -39
  57. hatchet_sdk/v0/clients/rest/models/create_api_token_request.py +0 -92
  58. hatchet_sdk/v0/clients/rest/models/create_api_token_response.py +0 -83
  59. hatchet_sdk/v0/clients/rest/models/create_cron_workflow_trigger_request.py +0 -98
  60. hatchet_sdk/v0/clients/rest/models/create_event_request.py +0 -95
  61. hatchet_sdk/v0/clients/rest/models/create_pull_request_from_step_run.py +0 -83
  62. hatchet_sdk/v0/clients/rest/models/create_sns_integration_request.py +0 -85
  63. hatchet_sdk/v0/clients/rest/models/create_tenant_alert_email_group_request.py +0 -83
  64. hatchet_sdk/v0/clients/rest/models/create_tenant_invite_request.py +0 -86
  65. hatchet_sdk/v0/clients/rest/models/create_tenant_request.py +0 -84
  66. hatchet_sdk/v0/clients/rest/models/cron_workflows.py +0 -131
  67. hatchet_sdk/v0/clients/rest/models/cron_workflows_list.py +0 -110
  68. hatchet_sdk/v0/clients/rest/models/cron_workflows_method.py +0 -37
  69. hatchet_sdk/v0/clients/rest/models/cron_workflows_order_by_field.py +0 -37
  70. hatchet_sdk/v0/clients/rest/models/event.py +0 -143
  71. hatchet_sdk/v0/clients/rest/models/event_data.py +0 -83
  72. hatchet_sdk/v0/clients/rest/models/event_key_list.py +0 -98
  73. hatchet_sdk/v0/clients/rest/models/event_list.py +0 -110
  74. hatchet_sdk/v0/clients/rest/models/event_order_by_direction.py +0 -37
  75. hatchet_sdk/v0/clients/rest/models/event_order_by_field.py +0 -36
  76. hatchet_sdk/v0/clients/rest/models/event_update_cancel200_response.py +0 -85
  77. hatchet_sdk/v0/clients/rest/models/event_workflow_run_summary.py +0 -116
  78. hatchet_sdk/v0/clients/rest/models/events.py +0 -110
  79. hatchet_sdk/v0/clients/rest/models/get_step_run_diff_response.py +0 -100
  80. hatchet_sdk/v0/clients/rest/models/github_app_installation.py +0 -107
  81. hatchet_sdk/v0/clients/rest/models/github_branch.py +0 -86
  82. hatchet_sdk/v0/clients/rest/models/github_repo.py +0 -86
  83. hatchet_sdk/v0/clients/rest/models/info_get_version200_response.py +0 -83
  84. hatchet_sdk/v0/clients/rest/models/job.py +0 -132
  85. hatchet_sdk/v0/clients/rest/models/job_run.py +0 -176
  86. hatchet_sdk/v0/clients/rest/models/job_run_status.py +0 -41
  87. hatchet_sdk/v0/clients/rest/models/link_github_repository_request.py +0 -106
  88. hatchet_sdk/v0/clients/rest/models/list_api_tokens_response.py +0 -110
  89. hatchet_sdk/v0/clients/rest/models/list_github_app_installations_response.py +0 -112
  90. hatchet_sdk/v0/clients/rest/models/list_pull_requests_response.py +0 -100
  91. hatchet_sdk/v0/clients/rest/models/list_slack_webhooks.py +0 -110
  92. hatchet_sdk/v0/clients/rest/models/list_sns_integrations.py +0 -110
  93. hatchet_sdk/v0/clients/rest/models/log_line.py +0 -94
  94. hatchet_sdk/v0/clients/rest/models/log_line_level.py +0 -39
  95. hatchet_sdk/v0/clients/rest/models/log_line_list.py +0 -110
  96. hatchet_sdk/v0/clients/rest/models/log_line_order_by_direction.py +0 -37
  97. hatchet_sdk/v0/clients/rest/models/log_line_order_by_field.py +0 -36
  98. hatchet_sdk/v0/clients/rest/models/pagination_response.py +0 -95
  99. hatchet_sdk/v0/clients/rest/models/pull_request.py +0 -112
  100. hatchet_sdk/v0/clients/rest/models/pull_request_state.py +0 -37
  101. hatchet_sdk/v0/clients/rest/models/queue_metrics.py +0 -97
  102. hatchet_sdk/v0/clients/rest/models/rate_limit.py +0 -117
  103. hatchet_sdk/v0/clients/rest/models/rate_limit_list.py +0 -110
  104. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_direction.py +0 -37
  105. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_field.py +0 -38
  106. hatchet_sdk/v0/clients/rest/models/recent_step_runs.py +0 -118
  107. hatchet_sdk/v0/clients/rest/models/reject_invite_request.py +0 -83
  108. hatchet_sdk/v0/clients/rest/models/replay_event_request.py +0 -85
  109. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_request.py +0 -85
  110. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_response.py +0 -100
  111. hatchet_sdk/v0/clients/rest/models/rerun_step_run_request.py +0 -83
  112. hatchet_sdk/v0/clients/rest/models/schedule_workflow_run_request.py +0 -92
  113. hatchet_sdk/v0/clients/rest/models/scheduled_run_status.py +0 -42
  114. hatchet_sdk/v0/clients/rest/models/scheduled_workflows.py +0 -149
  115. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_list.py +0 -110
  116. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_method.py +0 -37
  117. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_order_by_field.py +0 -37
  118. hatchet_sdk/v0/clients/rest/models/semaphore_slots.py +0 -113
  119. hatchet_sdk/v0/clients/rest/models/slack_webhook.py +0 -127
  120. hatchet_sdk/v0/clients/rest/models/sns_integration.py +0 -114
  121. hatchet_sdk/v0/clients/rest/models/step.py +0 -123
  122. hatchet_sdk/v0/clients/rest/models/step_run.py +0 -202
  123. hatchet_sdk/v0/clients/rest/models/step_run_archive.py +0 -142
  124. hatchet_sdk/v0/clients/rest/models/step_run_archive_list.py +0 -110
  125. hatchet_sdk/v0/clients/rest/models/step_run_diff.py +0 -91
  126. hatchet_sdk/v0/clients/rest/models/step_run_event.py +0 -122
  127. hatchet_sdk/v0/clients/rest/models/step_run_event_list.py +0 -110
  128. hatchet_sdk/v0/clients/rest/models/step_run_event_reason.py +0 -52
  129. hatchet_sdk/v0/clients/rest/models/step_run_event_severity.py +0 -38
  130. hatchet_sdk/v0/clients/rest/models/step_run_status.py +0 -44
  131. hatchet_sdk/v0/clients/rest/models/tenant.py +0 -118
  132. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group.py +0 -98
  133. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group_list.py +0 -112
  134. hatchet_sdk/v0/clients/rest/models/tenant_alerting_settings.py +0 -143
  135. hatchet_sdk/v0/clients/rest/models/tenant_invite.py +0 -120
  136. hatchet_sdk/v0/clients/rest/models/tenant_invite_list.py +0 -110
  137. hatchet_sdk/v0/clients/rest/models/tenant_list.py +0 -110
  138. hatchet_sdk/v0/clients/rest/models/tenant_member.py +0 -123
  139. hatchet_sdk/v0/clients/rest/models/tenant_member_list.py +0 -110
  140. hatchet_sdk/v0/clients/rest/models/tenant_member_role.py +0 -38
  141. hatchet_sdk/v0/clients/rest/models/tenant_queue_metrics.py +0 -116
  142. hatchet_sdk/v0/clients/rest/models/tenant_resource.py +0 -40
  143. hatchet_sdk/v0/clients/rest/models/tenant_resource_limit.py +0 -135
  144. hatchet_sdk/v0/clients/rest/models/tenant_resource_policy.py +0 -102
  145. hatchet_sdk/v0/clients/rest/models/tenant_step_run_queue_metrics.py +0 -83
  146. hatchet_sdk/v0/clients/rest/models/trigger_workflow_run_request.py +0 -91
  147. hatchet_sdk/v0/clients/rest/models/update_tenant_alert_email_group_request.py +0 -83
  148. hatchet_sdk/v0/clients/rest/models/update_tenant_invite_request.py +0 -85
  149. hatchet_sdk/v0/clients/rest/models/update_tenant_request.py +0 -137
  150. hatchet_sdk/v0/clients/rest/models/update_worker_request.py +0 -87
  151. hatchet_sdk/v0/clients/rest/models/user.py +0 -126
  152. hatchet_sdk/v0/clients/rest/models/user_change_password_request.py +0 -88
  153. hatchet_sdk/v0/clients/rest/models/user_login_request.py +0 -86
  154. hatchet_sdk/v0/clients/rest/models/user_register_request.py +0 -91
  155. hatchet_sdk/v0/clients/rest/models/user_tenant_memberships_list.py +0 -110
  156. hatchet_sdk/v0/clients/rest/models/user_tenant_public.py +0 -86
  157. hatchet_sdk/v0/clients/rest/models/webhook_worker.py +0 -100
  158. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_request.py +0 -94
  159. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_response.py +0 -98
  160. hatchet_sdk/v0/clients/rest/models/webhook_worker_created.py +0 -102
  161. hatchet_sdk/v0/clients/rest/models/webhook_worker_list_response.py +0 -110
  162. hatchet_sdk/v0/clients/rest/models/webhook_worker_request.py +0 -102
  163. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_list_response.py +0 -104
  164. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_method.py +0 -38
  165. hatchet_sdk/v0/clients/rest/models/worker.py +0 -239
  166. hatchet_sdk/v0/clients/rest/models/worker_label.py +0 -102
  167. hatchet_sdk/v0/clients/rest/models/worker_list.py +0 -110
  168. hatchet_sdk/v0/clients/rest/models/worker_runtime_info.py +0 -103
  169. hatchet_sdk/v0/clients/rest/models/worker_runtime_sdks.py +0 -38
  170. hatchet_sdk/v0/clients/rest/models/worker_type.py +0 -38
  171. hatchet_sdk/v0/clients/rest/models/workflow.py +0 -165
  172. hatchet_sdk/v0/clients/rest/models/workflow_concurrency.py +0 -107
  173. hatchet_sdk/v0/clients/rest/models/workflow_deployment_config.py +0 -136
  174. hatchet_sdk/v0/clients/rest/models/workflow_kind.py +0 -38
  175. hatchet_sdk/v0/clients/rest/models/workflow_list.py +0 -120
  176. hatchet_sdk/v0/clients/rest/models/workflow_metrics.py +0 -97
  177. hatchet_sdk/v0/clients/rest/models/workflow_run.py +0 -188
  178. hatchet_sdk/v0/clients/rest/models/workflow_run_cancel200_response.py +0 -85
  179. hatchet_sdk/v0/clients/rest/models/workflow_run_list.py +0 -110
  180. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_direction.py +0 -37
  181. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_field.py +0 -39
  182. hatchet_sdk/v0/clients/rest/models/workflow_run_shape.py +0 -186
  183. hatchet_sdk/v0/clients/rest/models/workflow_run_status.py +0 -42
  184. hatchet_sdk/v0/clients/rest/models/workflow_run_triggered_by.py +0 -112
  185. hatchet_sdk/v0/clients/rest/models/workflow_runs_cancel_request.py +0 -85
  186. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics.py +0 -94
  187. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics_counts.py +0 -104
  188. hatchet_sdk/v0/clients/rest/models/workflow_tag.py +0 -84
  189. hatchet_sdk/v0/clients/rest/models/workflow_trigger_cron_ref.py +0 -86
  190. hatchet_sdk/v0/clients/rest/models/workflow_trigger_event_ref.py +0 -86
  191. hatchet_sdk/v0/clients/rest/models/workflow_triggers.py +0 -141
  192. hatchet_sdk/v0/clients/rest/models/workflow_update_request.py +0 -85
  193. hatchet_sdk/v0/clients/rest/models/workflow_version.py +0 -170
  194. hatchet_sdk/v0/clients/rest/models/workflow_version_concurrency.py +0 -114
  195. hatchet_sdk/v0/clients/rest/models/workflow_version_definition.py +0 -85
  196. hatchet_sdk/v0/clients/rest/models/workflow_version_meta.py +0 -123
  197. hatchet_sdk/v0/clients/rest/models/workflow_workers_count.py +0 -95
  198. hatchet_sdk/v0/clients/rest/rest.py +0 -187
  199. hatchet_sdk/v0/clients/rest/tenacity_utils.py +0 -39
  200. hatchet_sdk/v0/clients/rest_client.py +0 -622
  201. hatchet_sdk/v0/clients/run_event_listener.py +0 -260
  202. hatchet_sdk/v0/clients/workflow_listener.py +0 -277
  203. hatchet_sdk/v0/connection.py +0 -63
  204. hatchet_sdk/v0/context/__init__.py +0 -1
  205. hatchet_sdk/v0/context/context.py +0 -446
  206. hatchet_sdk/v0/context/worker_context.py +0 -28
  207. hatchet_sdk/v0/features/cron.py +0 -286
  208. hatchet_sdk/v0/features/scheduled.py +0 -248
  209. hatchet_sdk/v0/hatchet.py +0 -310
  210. hatchet_sdk/v0/labels.py +0 -10
  211. hatchet_sdk/v0/loader.py +0 -244
  212. hatchet_sdk/v0/metadata.py +0 -2
  213. hatchet_sdk/v0/opentelemetry/instrumentor.py +0 -393
  214. hatchet_sdk/v0/rate_limit.py +0 -126
  215. hatchet_sdk/v0/semver.py +0 -30
  216. hatchet_sdk/v0/token.py +0 -27
  217. hatchet_sdk/v0/utils/aio_utils.py +0 -137
  218. hatchet_sdk/v0/utils/backoff.py +0 -9
  219. hatchet_sdk/v0/utils/types.py +0 -8
  220. hatchet_sdk/v0/utils/typing.py +0 -12
  221. hatchet_sdk/v0/v2/callable.py +0 -202
  222. hatchet_sdk/v0/v2/concurrency.py +0 -47
  223. hatchet_sdk/v0/v2/hatchet.py +0 -224
  224. hatchet_sdk/v0/worker/__init__.py +0 -1
  225. hatchet_sdk/v0/worker/action_listener_process.py +0 -294
  226. hatchet_sdk/v0/worker/runner/run_loop_manager.py +0 -112
  227. hatchet_sdk/v0/worker/runner/runner.py +0 -460
  228. hatchet_sdk/v0/worker/runner/utils/capture_logs.py +0 -81
  229. hatchet_sdk/v0/worker/runner/utils/error_with_traceback.py +0 -6
  230. hatchet_sdk/v0/worker/worker.py +0 -391
  231. hatchet_sdk/v0/workflow.py +0 -261
  232. hatchet_sdk/v0/workflow_run.py +0 -59
  233. {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/WHEEL +0 -0
  234. {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/entry_points.txt +0 -0
@@ -1,391 +0,0 @@
1
- import asyncio
2
- import multiprocessing
3
- import multiprocessing.context
4
- import os
5
- import signal
6
- import sys
7
- from concurrent.futures import Future
8
- from dataclasses import dataclass, field
9
- from enum import Enum
10
- from multiprocessing import Queue
11
- from multiprocessing.process import BaseProcess
12
- from types import FrameType
13
- from typing import Any, Callable, TypeVar, get_type_hints
14
-
15
- from aiohttp import web
16
- from aiohttp.web_request import Request
17
- from aiohttp.web_response import Response
18
- from prometheus_client import CONTENT_TYPE_LATEST, Gauge, generate_latest
19
-
20
- from hatchet_sdk.contracts.workflows_pb2 import CreateWorkflowVersionOpts
21
- from hatchet_sdk.logger import logger
22
- from hatchet_sdk.v0 import Context
23
- from hatchet_sdk.v0.client import Client, new_client_raw
24
- from hatchet_sdk.v0.loader import ClientConfig
25
- from hatchet_sdk.v0.utils.types import WorkflowValidator
26
- from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
27
- from hatchet_sdk.v0.v2.callable import HatchetCallable
28
- from hatchet_sdk.v0.v2.concurrency import ConcurrencyFunction
29
- from hatchet_sdk.v0.worker.action_listener_process import worker_action_listener_process
30
- from hatchet_sdk.v0.worker.runner.run_loop_manager import WorkerActionRunLoopManager
31
- from hatchet_sdk.v0.workflow import WorkflowInterface
32
-
33
- T = TypeVar("T")
34
-
35
-
36
- class WorkerStatus(Enum):
37
- INITIALIZED = 1
38
- STARTING = 2
39
- HEALTHY = 3
40
- UNHEALTHY = 4
41
-
42
-
43
- @dataclass
44
- class WorkerStartOptions:
45
- loop: asyncio.AbstractEventLoop | None = field(default=None)
46
-
47
-
48
- TWorkflow = TypeVar("TWorkflow", bound=object)
49
-
50
-
51
- class Worker:
52
- def __init__(
53
- self,
54
- name: str,
55
- config: ClientConfig = ClientConfig(),
56
- max_runs: int | None = None,
57
- labels: dict[str, str | int] = {},
58
- debug: bool = False,
59
- owned_loop: bool = True,
60
- handle_kill: bool = True,
61
- ) -> None:
62
- self.name = name
63
- self.config = config
64
- self.max_runs = max_runs
65
- self.debug = debug
66
- self.labels = labels
67
- self.handle_kill = handle_kill
68
- self.owned_loop = owned_loop
69
-
70
- self.client: Client
71
-
72
- self.action_registry: dict[str, Callable[[Context], Any]] = {}
73
- self.validator_registry: dict[str, WorkflowValidator] = {}
74
-
75
- self.killing: bool = False
76
- self._status: WorkerStatus
77
-
78
- self.action_listener_process: BaseProcess
79
- self.action_listener_health_check: asyncio.Task[Any]
80
- self.action_runner: WorkerActionRunLoopManager
81
-
82
- self.ctx = multiprocessing.get_context("spawn")
83
-
84
- self.action_queue: "Queue[Any]" = self.ctx.Queue()
85
- self.event_queue: "Queue[Any]" = self.ctx.Queue()
86
-
87
- self.loop: asyncio.AbstractEventLoop
88
-
89
- self.client = new_client_raw(self.config, self.debug)
90
- self.name = self.client.config.namespace + self.name
91
-
92
- self._setup_signal_handlers()
93
-
94
- self.worker_status_gauge = Gauge(
95
- "hatchet_worker_status", "Current status of the Hatchet worker"
96
- )
97
-
98
- def register_function(self, action: str, func: Callable[[Context], Any]) -> None:
99
- self.action_registry[action] = func
100
-
101
- def register_workflow_from_opts(
102
- self, name: str, opts: CreateWorkflowVersionOpts
103
- ) -> None:
104
- try:
105
- self.client.admin.put_workflow(opts.name, opts)
106
- except Exception as e:
107
- logger.error(f"failed to register workflow: {opts.name}")
108
- logger.error(e)
109
- sys.exit(1)
110
-
111
- def register_workflow(self, workflow: TWorkflow) -> None:
112
- ## Hack for typing
113
- assert isinstance(workflow, WorkflowInterface)
114
-
115
- namespace = self.client.config.namespace
116
-
117
- try:
118
- self.client.admin.put_workflow(
119
- workflow.get_name(namespace), workflow.get_create_opts(namespace)
120
- )
121
- except Exception as e:
122
- logger.error(f"failed to register workflow: {workflow.get_name(namespace)}")
123
- logger.error(e)
124
- sys.exit(1)
125
-
126
- def create_action_function(
127
- action_func: Callable[..., T]
128
- ) -> Callable[[Context], T]:
129
- def action_function(context: Context) -> T:
130
- return action_func(workflow, context)
131
-
132
- if asyncio.iscoroutinefunction(action_func):
133
- setattr(action_function, "is_coroutine", True)
134
- else:
135
- setattr(action_function, "is_coroutine", False)
136
-
137
- return action_function
138
-
139
- for action_name, action_func in workflow.get_actions(namespace):
140
- self.action_registry[action_name] = create_action_function(action_func)
141
- return_type = get_type_hints(action_func).get("return")
142
-
143
- self.validator_registry[action_name] = WorkflowValidator(
144
- workflow_input=workflow.input_validator,
145
- step_output=return_type if is_basemodel_subclass(return_type) else None,
146
- )
147
-
148
- def status(self) -> WorkerStatus:
149
- return self._status
150
-
151
- def setup_loop(self, loop: asyncio.AbstractEventLoop | None = None) -> bool:
152
- try:
153
- loop = loop or asyncio.get_running_loop()
154
- self.loop = loop
155
- created_loop = False
156
- logger.debug("using existing event loop")
157
- return created_loop
158
- except RuntimeError:
159
- self.loop = asyncio.new_event_loop()
160
- logger.debug("creating new event loop")
161
- asyncio.set_event_loop(self.loop)
162
- created_loop = True
163
- return created_loop
164
-
165
- async def health_check_handler(self, request: Request) -> Response:
166
- status = self.status()
167
-
168
- return web.json_response({"status": status.name})
169
-
170
- async def metrics_handler(self, request: Request) -> Response:
171
- self.worker_status_gauge.set(1 if self.status() == WorkerStatus.HEALTHY else 0)
172
-
173
- return web.Response(body=generate_latest(), content_type="text/plain")
174
-
175
- async def start_health_server(self) -> None:
176
- port = self.config.worker_healthcheck_port or 8001
177
-
178
- app = web.Application()
179
- app.add_routes(
180
- [
181
- web.get("/health", self.health_check_handler),
182
- web.get("/metrics", self.metrics_handler),
183
- ]
184
- )
185
-
186
- runner = web.AppRunner(app)
187
-
188
- try:
189
- await runner.setup()
190
- await web.TCPSite(runner, "0.0.0.0", port).start()
191
- except Exception as e:
192
- logger.error("failed to start healthcheck server")
193
- logger.error(str(e))
194
- return
195
-
196
- logger.info(f"healthcheck server running on port {port}")
197
-
198
- def start(
199
- self, options: WorkerStartOptions = WorkerStartOptions()
200
- ) -> Future[asyncio.Task[None]]:
201
- self.owned_loop = self.setup_loop(options.loop)
202
-
203
- f = asyncio.run_coroutine_threadsafe(
204
- self._async_start(options, _from_start=True), self.loop
205
- )
206
-
207
- # start the loop and wait until its closed
208
- if self.owned_loop:
209
- self.loop.run_forever()
210
-
211
- if self.handle_kill:
212
- sys.exit(0)
213
-
214
- return f
215
-
216
- ## Start methods
217
- async def _async_start(
218
- self,
219
- options: WorkerStartOptions = WorkerStartOptions(),
220
- _from_start: bool = False,
221
- ) -> asyncio.Task[None]:
222
- main_pid = os.getpid()
223
- logger.info("------------------------------------------")
224
- logger.info("STARTING HATCHET...")
225
- logger.debug(f"worker runtime starting on PID: {main_pid}")
226
-
227
- self._status = WorkerStatus.STARTING
228
-
229
- if len(self.action_registry.keys()) == 0:
230
- raise ValueError(
231
- "no actions registered, register workflows or actions before starting worker"
232
- )
233
-
234
- # non blocking setup
235
- if not _from_start:
236
- self.setup_loop(options.loop)
237
-
238
- if self.config.worker_healthcheck_enabled:
239
- await self.start_health_server()
240
-
241
- self.action_listener_process = self._start_listener()
242
-
243
- self.action_runner = self._run_action_runner()
244
-
245
- self.action_listener_health_check = self.loop.create_task(
246
- self._check_listener_health()
247
- )
248
-
249
- return await self.action_listener_health_check
250
-
251
- def _run_action_runner(self) -> WorkerActionRunLoopManager:
252
- # Retrieve the shared queue
253
- return WorkerActionRunLoopManager(
254
- self.name,
255
- self.action_registry,
256
- self.validator_registry,
257
- self.max_runs,
258
- self.config,
259
- self.action_queue,
260
- self.event_queue,
261
- self.loop,
262
- self.handle_kill,
263
- self.client.debug,
264
- self.labels,
265
- )
266
-
267
- def _start_listener(self) -> multiprocessing.context.SpawnProcess:
268
- action_list = [str(key) for key in self.action_registry.keys()]
269
-
270
- try:
271
- process = self.ctx.Process(
272
- target=worker_action_listener_process,
273
- args=(
274
- self.name,
275
- action_list,
276
- self.max_runs,
277
- self.config,
278
- self.action_queue,
279
- self.event_queue,
280
- self.handle_kill,
281
- self.client.debug,
282
- self.labels,
283
- ),
284
- )
285
- process.start()
286
- logger.debug(f"action listener starting on PID: {process.pid}")
287
-
288
- return process
289
- except Exception as e:
290
- logger.error(f"failed to start action listener: {e}")
291
- sys.exit(1)
292
-
293
- async def _check_listener_health(self) -> None:
294
- logger.debug("starting action listener health check...")
295
- try:
296
- while not self.killing:
297
- if (
298
- self.action_listener_process is None
299
- or not self.action_listener_process.is_alive()
300
- ):
301
- logger.debug("child action listener process killed...")
302
- self._status = WorkerStatus.UNHEALTHY
303
- if not self.killing:
304
- self.loop.create_task(self.exit_gracefully())
305
- break
306
- else:
307
- self._status = WorkerStatus.HEALTHY
308
- await asyncio.sleep(1)
309
- except Exception as e:
310
- logger.error(f"error checking listener health: {e}")
311
-
312
- ## Cleanup methods
313
- def _setup_signal_handlers(self) -> None:
314
- signal.signal(signal.SIGTERM, self._handle_exit_signal)
315
- signal.signal(signal.SIGINT, self._handle_exit_signal)
316
- signal.signal(signal.SIGQUIT, self._handle_force_quit_signal)
317
-
318
- def _handle_exit_signal(self, signum: int, frame: FrameType | None) -> None:
319
- sig_name = "SIGTERM" if signum == signal.SIGTERM else "SIGINT"
320
- logger.info(f"received signal {sig_name}...")
321
- self.loop.create_task(self.exit_gracefully())
322
-
323
- def _handle_force_quit_signal(self, signum: int, frame: FrameType | None) -> None:
324
- logger.info("received SIGQUIT...")
325
- self.exit_forcefully()
326
-
327
- async def close(self) -> None:
328
- logger.info(f"closing worker '{self.name}'...")
329
- self.killing = True
330
- # self.action_queue.close()
331
- # self.event_queue.close()
332
-
333
- if self.action_runner is not None:
334
- self.action_runner.cleanup()
335
-
336
- await self.action_listener_health_check
337
-
338
- async def exit_gracefully(self) -> None:
339
- logger.debug(f"gracefully stopping worker: {self.name}")
340
-
341
- if self.killing:
342
- return self.exit_forcefully()
343
-
344
- self.killing = True
345
-
346
- await self.action_runner.wait_for_tasks()
347
-
348
- await self.action_runner.exit_gracefully()
349
-
350
- if self.action_listener_process and self.action_listener_process.is_alive():
351
- self.action_listener_process.kill()
352
-
353
- await self.close()
354
- if self.loop and self.owned_loop:
355
- self.loop.stop()
356
-
357
- logger.info("👋")
358
-
359
- def exit_forcefully(self) -> None:
360
- self.killing = True
361
-
362
- logger.debug(f"forcefully stopping worker: {self.name}")
363
-
364
- self.close()
365
-
366
- if self.action_listener_process:
367
- self.action_listener_process.kill() # Forcefully kill the process
368
-
369
- logger.info("👋")
370
- sys.exit(
371
- 1
372
- ) # Exit immediately TODO - should we exit with 1 here, there may be other workers to cleanup
373
-
374
-
375
- def register_on_worker(callable: HatchetCallable[T], worker: Worker) -> None:
376
- worker.register_function(callable.get_action_name(), callable)
377
-
378
- if callable.function_on_failure is not None:
379
- worker.register_function(
380
- callable.function_on_failure.get_action_name(), callable.function_on_failure
381
- )
382
-
383
- if callable.function_concurrency is not None:
384
- worker.register_function(
385
- callable.function_concurrency.get_action_name(),
386
- callable.function_concurrency,
387
- )
388
-
389
- opts = callable.to_workflow_opts()
390
-
391
- worker.register_workflow_from_opts(opts.name, opts)
@@ -1,261 +0,0 @@
1
- import functools
2
- from typing import (
3
- Any,
4
- Callable,
5
- Protocol,
6
- Type,
7
- TypeVar,
8
- Union,
9
- cast,
10
- get_type_hints,
11
- runtime_checkable,
12
- )
13
-
14
- from pydantic import BaseModel
15
-
16
- from hatchet_sdk.contracts.workflows_pb2 import (
17
- CreateWorkflowJobOpts,
18
- CreateWorkflowStepOpts,
19
- CreateWorkflowVersionOpts,
20
- StickyStrategy,
21
- WorkflowConcurrencyOpts,
22
- WorkflowKind,
23
- )
24
- from hatchet_sdk.logger import logger
25
- from hatchet_sdk.v0 import ConcurrencyLimitStrategy
26
- from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
27
-
28
-
29
- class WorkflowStepProtocol(Protocol):
30
- def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
31
-
32
- __name__: str
33
-
34
- _step_name: str
35
- _step_timeout: str | None
36
- _step_parents: list[str]
37
- _step_retries: int | None
38
- _step_rate_limits: list[str] | None
39
- _step_desired_worker_labels: dict[str, str]
40
- _step_backoff_factor: float | None
41
- _step_backoff_max_seconds: int | None
42
-
43
- _concurrency_fn_name: str
44
- _concurrency_max_runs: int | None
45
- _concurrency_limit_strategy: str | None
46
-
47
- _on_failure_step_name: str
48
- _on_failure_step_timeout: str | None
49
- _on_failure_step_retries: int
50
- _on_failure_step_rate_limits: list[str] | None
51
- _on_failure_step_backoff_factor: float | None
52
- _on_failure_step_backoff_max_seconds: int | None
53
-
54
-
55
- StepsType = list[tuple[str, WorkflowStepProtocol]]
56
-
57
- T = TypeVar("T")
58
- TW = TypeVar("TW", bound="WorkflowInterface")
59
-
60
-
61
- class ConcurrencyExpression:
62
- """
63
- Defines concurrency limits for a workflow using a CEL expression.
64
-
65
- Args:
66
- expression (str): CEL expression to determine concurrency grouping. (i.e. "input.user_id")
67
- max_runs (int): Maximum number of concurrent workflow runs.
68
- limit_strategy (ConcurrencyLimitStrategy): Strategy for handling limit violations.
69
-
70
- Example:
71
- ConcurrencyExpression("input.user_id", 5, ConcurrencyLimitStrategy.CANCEL_IN_PROGRESS)
72
- """
73
-
74
- def __init__(
75
- self, expression: str, max_runs: int, limit_strategy: ConcurrencyLimitStrategy
76
- ):
77
- self.expression = expression
78
- self.max_runs = max_runs
79
- self.limit_strategy = limit_strategy
80
-
81
-
82
- @runtime_checkable
83
- class WorkflowInterface(Protocol):
84
- def get_name(self, namespace: str) -> str: ...
85
-
86
- def get_actions(self, namespace: str) -> list[tuple[str, Callable[..., Any]]]: ...
87
-
88
- def get_create_opts(self, namespace: str) -> Any: ...
89
-
90
- on_events: list[str] | None
91
- on_crons: list[str] | None
92
- name: str
93
- version: str
94
- timeout: str
95
- schedule_timeout: str
96
- sticky: Union[StickyStrategy.Value, None] # type: ignore[name-defined]
97
- default_priority: int | None
98
- concurrency_expression: ConcurrencyExpression | None
99
- input_validator: Type[BaseModel] | None
100
-
101
-
102
- class WorkflowMeta(type):
103
- def __new__(
104
- cls: Type["WorkflowMeta"],
105
- name: str,
106
- bases: tuple[type, ...],
107
- attrs: dict[str, Any],
108
- ) -> "WorkflowMeta":
109
- def _create_steps_actions_list(name: str) -> StepsType:
110
- return [
111
- (getattr(func, name), attrs.pop(func_name))
112
- for func_name, func in list(attrs.items())
113
- if hasattr(func, name)
114
- ]
115
-
116
- concurrencyActions = _create_steps_actions_list("_concurrency_fn_name")
117
- steps = _create_steps_actions_list("_step_name")
118
-
119
- onFailureSteps = _create_steps_actions_list("_on_failure_step_name")
120
-
121
- # Define __init__ and get_step_order methods
122
- original_init = attrs.get("__init__") # Get the original __init__ if it exists
123
-
124
- def __init__(self: TW, *args: Any, **kwargs: Any) -> None:
125
- if original_init:
126
- original_init(self, *args, **kwargs) # Call original __init__
127
-
128
- def get_service_name(namespace: str) -> str:
129
- return f"{namespace}{name.lower()}"
130
-
131
- @functools.cache
132
- def get_actions(self: TW, namespace: str) -> StepsType:
133
- serviceName = get_service_name(namespace)
134
-
135
- func_actions = [
136
- (serviceName + ":" + func_name, func) for func_name, func in steps
137
- ]
138
- concurrency_actions = [
139
- (serviceName + ":" + func_name, func)
140
- for func_name, func in concurrencyActions
141
- ]
142
- onFailure_actions = [
143
- (serviceName + ":" + func_name, func)
144
- for func_name, func in onFailureSteps
145
- ]
146
-
147
- return func_actions + concurrency_actions + onFailure_actions
148
-
149
- # Add these methods and steps to class attributes
150
- attrs["__init__"] = __init__
151
- attrs["get_actions"] = get_actions
152
-
153
- for step_name, step_func in steps:
154
- attrs[step_name] = step_func
155
-
156
- def get_name(self: TW, namespace: str) -> str:
157
- return namespace + cast(str, attrs["name"])
158
-
159
- attrs["get_name"] = get_name
160
-
161
- cron_triggers = attrs["on_crons"]
162
- version = attrs["version"]
163
- schedule_timeout = attrs["schedule_timeout"]
164
- sticky = attrs["sticky"]
165
- default_priority = attrs["default_priority"]
166
-
167
- @functools.cache
168
- def get_create_opts(self: TW, namespace: str) -> CreateWorkflowVersionOpts:
169
- serviceName = get_service_name(namespace)
170
- name = self.get_name(namespace)
171
- event_triggers = [namespace + event for event in attrs["on_events"]]
172
- createStepOpts: list[CreateWorkflowStepOpts] = [
173
- CreateWorkflowStepOpts(
174
- readable_id=step_name,
175
- action=serviceName + ":" + step_name,
176
- timeout=func._step_timeout or "60s",
177
- inputs="{}",
178
- parents=[x for x in func._step_parents],
179
- retries=func._step_retries,
180
- rate_limits=func._step_rate_limits, # type: ignore[arg-type]
181
- worker_labels=func._step_desired_worker_labels, # type: ignore[arg-type]
182
- backoff_factor=func._step_backoff_factor,
183
- backoff_max_seconds=func._step_backoff_max_seconds,
184
- )
185
- for step_name, func in steps
186
- ]
187
-
188
- concurrency: WorkflowConcurrencyOpts | None = None
189
-
190
- if len(concurrencyActions) > 0:
191
- action = concurrencyActions[0]
192
-
193
- concurrency = WorkflowConcurrencyOpts(
194
- action=serviceName + ":" + action[0],
195
- max_runs=action[1]._concurrency_max_runs,
196
- limit_strategy=action[1]._concurrency_limit_strategy,
197
- )
198
-
199
- if self.concurrency_expression:
200
- concurrency = WorkflowConcurrencyOpts(
201
- expression=self.concurrency_expression.expression,
202
- max_runs=self.concurrency_expression.max_runs,
203
- limit_strategy=self.concurrency_expression.limit_strategy,
204
- )
205
-
206
- if len(concurrencyActions) > 0 and self.concurrency_expression:
207
- raise ValueError(
208
- "Error: Both concurrencyActions and concurrency_expression are defined. Please use only one concurrency configuration method."
209
- )
210
-
211
- on_failure_job: CreateWorkflowJobOpts | None = None
212
-
213
- if len(onFailureSteps) > 0:
214
- func_name, func = onFailureSteps[0]
215
- on_failure_job = CreateWorkflowJobOpts(
216
- name=name + "-on-failure",
217
- steps=[
218
- CreateWorkflowStepOpts(
219
- readable_id=func_name,
220
- action=serviceName + ":" + func_name,
221
- timeout=func._on_failure_step_timeout or "60s",
222
- inputs="{}",
223
- parents=[],
224
- retries=func._on_failure_step_retries,
225
- rate_limits=func._on_failure_step_rate_limits, # type: ignore[arg-type]
226
- backoff_factor=func._on_failure_step_backoff_factor,
227
- backoff_max_seconds=func._on_failure_step_backoff_max_seconds,
228
- )
229
- ],
230
- )
231
-
232
- validated_priority = (
233
- max(1, min(3, default_priority)) if default_priority else None
234
- )
235
- if validated_priority != default_priority:
236
- logger.warning(
237
- "Warning: Default Priority Must be between 1 and 3 -- inclusively. Adjusted to be within the range."
238
- )
239
-
240
- return CreateWorkflowVersionOpts(
241
- name=name,
242
- kind=WorkflowKind.DAG,
243
- version=version,
244
- event_triggers=event_triggers,
245
- cron_triggers=cron_triggers,
246
- schedule_timeout=schedule_timeout,
247
- sticky=sticky,
248
- jobs=[
249
- CreateWorkflowJobOpts(
250
- name=name,
251
- steps=createStepOpts,
252
- )
253
- ],
254
- on_failure_job=on_failure_job,
255
- concurrency=concurrency,
256
- default_priority=validated_priority,
257
- )
258
-
259
- attrs["get_create_opts"] = get_create_opts
260
-
261
- return super(WorkflowMeta, cls).__new__(cls, name, bases, attrs)
@@ -1,59 +0,0 @@
1
- import asyncio
2
- from typing import Any, Coroutine, Generic, Optional, TypedDict, TypeVar
3
-
4
- from hatchet_sdk.v0.clients.run_event_listener import (
5
- RunEventListener,
6
- RunEventListenerClient,
7
- )
8
- from hatchet_sdk.v0.clients.workflow_listener import PooledWorkflowRunListener
9
- from hatchet_sdk.v0.utils.aio_utils import EventLoopThread, get_active_event_loop
10
-
11
-
12
- class WorkflowRunRef:
13
- workflow_run_id: str
14
-
15
- def __init__(
16
- self,
17
- workflow_run_id: str,
18
- workflow_listener: PooledWorkflowRunListener,
19
- workflow_run_event_listener: RunEventListenerClient,
20
- ):
21
- self.workflow_run_id = workflow_run_id
22
- self.workflow_listener = workflow_listener
23
- self.workflow_run_event_listener = workflow_run_event_listener
24
-
25
- def __str__(self):
26
- return self.workflow_run_id
27
-
28
- def stream(self) -> RunEventListener:
29
- return self.workflow_run_event_listener.stream(self.workflow_run_id)
30
-
31
- def result(self) -> Coroutine:
32
- return self.workflow_listener.result(self.workflow_run_id)
33
-
34
- def sync_result(self) -> dict:
35
- coro = self.workflow_listener.result(self.workflow_run_id)
36
- loop = get_active_event_loop()
37
-
38
- if loop is None:
39
- loop = asyncio.new_event_loop()
40
- asyncio.set_event_loop(loop)
41
- try:
42
- return loop.run_until_complete(coro)
43
- finally:
44
- asyncio.set_event_loop(None)
45
- else:
46
- return loop.run_until_complete(coro)
47
-
48
-
49
- T = TypeVar("T")
50
-
51
-
52
- class RunRef(WorkflowRunRef, Generic[T]):
53
- async def result(self) -> T:
54
- res = await self.workflow_listener.result(self.workflow_run_id)
55
-
56
- if len(res) == 1:
57
- return list(res.values())[0]
58
-
59
- return res