hatchet-sdk 0.47.0__py3-none-any.whl → 1.0.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.
Files changed (303) hide show
  1. hatchet_sdk/__init__.py +25 -16
  2. hatchet_sdk/client.py +14 -39
  3. hatchet_sdk/clients/admin.py +203 -362
  4. hatchet_sdk/clients/dispatcher/action_listener.py +106 -84
  5. hatchet_sdk/clients/dispatcher/dispatcher.py +21 -21
  6. hatchet_sdk/clients/event_ts.py +23 -10
  7. hatchet_sdk/clients/events.py +96 -99
  8. hatchet_sdk/clients/rest/__init__.py +24 -0
  9. hatchet_sdk/clients/rest/api/__init__.py +2 -0
  10. hatchet_sdk/clients/rest/api/task_api.py +2174 -0
  11. hatchet_sdk/clients/rest/api/workflow_runs_api.py +638 -106
  12. hatchet_sdk/clients/rest/api_client.py +1 -1
  13. hatchet_sdk/clients/rest/configuration.py +8 -1
  14. hatchet_sdk/clients/rest/exceptions.py +21 -0
  15. hatchet_sdk/clients/rest/models/__init__.py +22 -0
  16. hatchet_sdk/clients/rest/models/tenant.py +4 -0
  17. hatchet_sdk/clients/rest/models/tenant_version.py +37 -0
  18. hatchet_sdk/clients/rest/models/update_tenant_request.py +7 -0
  19. hatchet_sdk/clients/rest/models/v1_cancel_task_request.py +104 -0
  20. hatchet_sdk/clients/rest/models/v1_dag_children.py +102 -0
  21. hatchet_sdk/clients/rest/models/v1_replay_task_request.py +104 -0
  22. hatchet_sdk/clients/rest/models/v1_task.py +174 -0
  23. hatchet_sdk/clients/rest/models/v1_task_event.py +118 -0
  24. hatchet_sdk/clients/rest/models/v1_task_event_list.py +110 -0
  25. hatchet_sdk/clients/rest/models/v1_task_event_type.py +55 -0
  26. hatchet_sdk/clients/rest/models/v1_task_filter.py +106 -0
  27. hatchet_sdk/clients/rest/models/v1_task_point_metric.py +92 -0
  28. hatchet_sdk/clients/rest/models/v1_task_point_metrics.py +100 -0
  29. hatchet_sdk/clients/rest/models/v1_task_run_metric.py +88 -0
  30. hatchet_sdk/clients/rest/models/v1_task_run_status.py +40 -0
  31. hatchet_sdk/clients/rest/models/v1_task_status.py +40 -0
  32. hatchet_sdk/clients/rest/models/v1_task_summary.py +212 -0
  33. hatchet_sdk/clients/rest/models/v1_task_summary_list.py +110 -0
  34. hatchet_sdk/clients/rest/models/v1_workflow_run.py +171 -0
  35. hatchet_sdk/clients/rest/models/v1_workflow_run_details.py +145 -0
  36. hatchet_sdk/clients/rest/models/v1_workflow_type.py +37 -0
  37. hatchet_sdk/clients/rest/models/workflow_run_shape_item_for_workflow_run_details.py +99 -0
  38. hatchet_sdk/clients/rest/rest.py +37 -26
  39. hatchet_sdk/clients/rest/tenacity_utils.py +1 -1
  40. hatchet_sdk/clients/rest_client.py +141 -116
  41. hatchet_sdk/clients/run_event_listener.py +66 -60
  42. hatchet_sdk/clients/workflow_listener.py +75 -66
  43. hatchet_sdk/config.py +117 -0
  44. hatchet_sdk/connection.py +27 -13
  45. hatchet_sdk/context/__init__.py +0 -1
  46. hatchet_sdk/context/context.py +118 -218
  47. hatchet_sdk/features/cron.py +43 -57
  48. hatchet_sdk/features/scheduled.py +60 -74
  49. hatchet_sdk/hatchet.py +192 -195
  50. hatchet_sdk/labels.py +4 -6
  51. hatchet_sdk/metadata.py +1 -1
  52. hatchet_sdk/opentelemetry/instrumentor.py +9 -5
  53. hatchet_sdk/rate_limit.py +9 -18
  54. hatchet_sdk/token.py +13 -9
  55. hatchet_sdk/utils/aio_utils.py +0 -40
  56. hatchet_sdk/utils/proto_enums.py +54 -0
  57. hatchet_sdk/utils/typing.py +9 -1
  58. hatchet_sdk/v0/__init__.py +251 -0
  59. hatchet_sdk/v0/client.py +119 -0
  60. hatchet_sdk/v0/clients/admin.py +541 -0
  61. hatchet_sdk/v0/clients/dispatcher/action_listener.py +422 -0
  62. hatchet_sdk/v0/clients/dispatcher/dispatcher.py +204 -0
  63. hatchet_sdk/v0/clients/event_ts.py +28 -0
  64. hatchet_sdk/v0/clients/events.py +182 -0
  65. hatchet_sdk/v0/clients/rest/__init__.py +307 -0
  66. hatchet_sdk/v0/clients/rest/api/__init__.py +19 -0
  67. hatchet_sdk/v0/clients/rest/api/api_token_api.py +858 -0
  68. hatchet_sdk/v0/clients/rest/api/default_api.py +2259 -0
  69. hatchet_sdk/v0/clients/rest/api/event_api.py +2548 -0
  70. hatchet_sdk/v0/clients/rest/api/github_api.py +331 -0
  71. hatchet_sdk/v0/clients/rest/api/healthcheck_api.py +483 -0
  72. hatchet_sdk/v0/clients/rest/api/log_api.py +449 -0
  73. hatchet_sdk/v0/clients/rest/api/metadata_api.py +728 -0
  74. hatchet_sdk/v0/clients/rest/api/rate_limits_api.py +423 -0
  75. hatchet_sdk/v0/clients/rest/api/slack_api.py +577 -0
  76. hatchet_sdk/v0/clients/rest/api/sns_api.py +872 -0
  77. hatchet_sdk/v0/clients/rest/api/step_run_api.py +2202 -0
  78. hatchet_sdk/v0/clients/rest/api/tenant_api.py +4430 -0
  79. hatchet_sdk/v0/clients/rest/api/user_api.py +2888 -0
  80. hatchet_sdk/v0/clients/rest/api/worker_api.py +858 -0
  81. hatchet_sdk/v0/clients/rest/api/workflow_api.py +6312 -0
  82. hatchet_sdk/v0/clients/rest/api/workflow_run_api.py +1932 -0
  83. hatchet_sdk/v0/clients/rest/api/workflow_runs_api.py +610 -0
  84. hatchet_sdk/v0/clients/rest/api_client.py +759 -0
  85. hatchet_sdk/v0/clients/rest/api_response.py +22 -0
  86. hatchet_sdk/v0/clients/rest/configuration.py +611 -0
  87. hatchet_sdk/v0/clients/rest/exceptions.py +200 -0
  88. hatchet_sdk/v0/clients/rest/models/__init__.py +274 -0
  89. hatchet_sdk/v0/clients/rest/models/accept_invite_request.py +83 -0
  90. hatchet_sdk/v0/clients/rest/models/api_error.py +102 -0
  91. hatchet_sdk/v0/clients/rest/models/api_errors.py +100 -0
  92. hatchet_sdk/v0/clients/rest/models/api_meta.py +144 -0
  93. hatchet_sdk/v0/clients/rest/models/api_meta_auth.py +85 -0
  94. hatchet_sdk/v0/clients/rest/models/api_meta_integration.py +88 -0
  95. hatchet_sdk/v0/clients/rest/models/api_meta_posthog.py +90 -0
  96. hatchet_sdk/v0/clients/rest/models/api_resource_meta.py +98 -0
  97. hatchet_sdk/v0/clients/rest/models/api_token.py +105 -0
  98. hatchet_sdk/v0/clients/rest/models/bulk_create_event_request.py +100 -0
  99. hatchet_sdk/v0/clients/rest/models/bulk_create_event_response.py +110 -0
  100. hatchet_sdk/v0/clients/rest/models/cancel_event_request.py +85 -0
  101. hatchet_sdk/v0/clients/rest/models/cancel_step_run_request.py +83 -0
  102. hatchet_sdk/v0/clients/rest/models/concurrency_limit_strategy.py +39 -0
  103. hatchet_sdk/v0/clients/rest/models/create_api_token_request.py +92 -0
  104. hatchet_sdk/v0/clients/rest/models/create_api_token_response.py +83 -0
  105. hatchet_sdk/v0/clients/rest/models/create_cron_workflow_trigger_request.py +98 -0
  106. hatchet_sdk/v0/clients/rest/models/create_event_request.py +95 -0
  107. hatchet_sdk/v0/clients/rest/models/create_pull_request_from_step_run.py +83 -0
  108. hatchet_sdk/v0/clients/rest/models/create_sns_integration_request.py +85 -0
  109. hatchet_sdk/v0/clients/rest/models/create_tenant_alert_email_group_request.py +83 -0
  110. hatchet_sdk/v0/clients/rest/models/create_tenant_invite_request.py +86 -0
  111. hatchet_sdk/v0/clients/rest/models/create_tenant_request.py +84 -0
  112. hatchet_sdk/v0/clients/rest/models/cron_workflows.py +131 -0
  113. hatchet_sdk/v0/clients/rest/models/cron_workflows_list.py +110 -0
  114. hatchet_sdk/v0/clients/rest/models/cron_workflows_method.py +37 -0
  115. hatchet_sdk/v0/clients/rest/models/cron_workflows_order_by_field.py +37 -0
  116. hatchet_sdk/v0/clients/rest/models/event.py +143 -0
  117. hatchet_sdk/v0/clients/rest/models/event_data.py +83 -0
  118. hatchet_sdk/v0/clients/rest/models/event_key_list.py +98 -0
  119. hatchet_sdk/v0/clients/rest/models/event_list.py +110 -0
  120. hatchet_sdk/v0/clients/rest/models/event_order_by_direction.py +37 -0
  121. hatchet_sdk/v0/clients/rest/models/event_order_by_field.py +36 -0
  122. hatchet_sdk/v0/clients/rest/models/event_update_cancel200_response.py +85 -0
  123. hatchet_sdk/v0/clients/rest/models/event_workflow_run_summary.py +116 -0
  124. hatchet_sdk/v0/clients/rest/models/events.py +110 -0
  125. hatchet_sdk/v0/clients/rest/models/get_step_run_diff_response.py +100 -0
  126. hatchet_sdk/v0/clients/rest/models/github_app_installation.py +107 -0
  127. hatchet_sdk/v0/clients/rest/models/github_branch.py +86 -0
  128. hatchet_sdk/v0/clients/rest/models/github_repo.py +86 -0
  129. hatchet_sdk/v0/clients/rest/models/info_get_version200_response.py +83 -0
  130. hatchet_sdk/v0/clients/rest/models/job.py +132 -0
  131. hatchet_sdk/v0/clients/rest/models/job_run.py +176 -0
  132. hatchet_sdk/v0/clients/rest/models/job_run_status.py +41 -0
  133. hatchet_sdk/v0/clients/rest/models/link_github_repository_request.py +106 -0
  134. hatchet_sdk/v0/clients/rest/models/list_api_tokens_response.py +110 -0
  135. hatchet_sdk/v0/clients/rest/models/list_github_app_installations_response.py +112 -0
  136. hatchet_sdk/v0/clients/rest/models/list_pull_requests_response.py +100 -0
  137. hatchet_sdk/v0/clients/rest/models/list_slack_webhooks.py +110 -0
  138. hatchet_sdk/v0/clients/rest/models/list_sns_integrations.py +110 -0
  139. hatchet_sdk/v0/clients/rest/models/log_line.py +94 -0
  140. hatchet_sdk/v0/clients/rest/models/log_line_level.py +39 -0
  141. hatchet_sdk/v0/clients/rest/models/log_line_list.py +110 -0
  142. hatchet_sdk/v0/clients/rest/models/log_line_order_by_direction.py +37 -0
  143. hatchet_sdk/v0/clients/rest/models/log_line_order_by_field.py +36 -0
  144. hatchet_sdk/v0/clients/rest/models/pagination_response.py +95 -0
  145. hatchet_sdk/v0/clients/rest/models/pull_request.py +112 -0
  146. hatchet_sdk/v0/clients/rest/models/pull_request_state.py +37 -0
  147. hatchet_sdk/v0/clients/rest/models/queue_metrics.py +97 -0
  148. hatchet_sdk/v0/clients/rest/models/rate_limit.py +117 -0
  149. hatchet_sdk/v0/clients/rest/models/rate_limit_list.py +110 -0
  150. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_direction.py +37 -0
  151. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_field.py +38 -0
  152. hatchet_sdk/v0/clients/rest/models/recent_step_runs.py +118 -0
  153. hatchet_sdk/v0/clients/rest/models/reject_invite_request.py +83 -0
  154. hatchet_sdk/v0/clients/rest/models/replay_event_request.py +85 -0
  155. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_request.py +85 -0
  156. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_response.py +100 -0
  157. hatchet_sdk/v0/clients/rest/models/rerun_step_run_request.py +83 -0
  158. hatchet_sdk/v0/clients/rest/models/schedule_workflow_run_request.py +92 -0
  159. hatchet_sdk/v0/clients/rest/models/scheduled_run_status.py +42 -0
  160. hatchet_sdk/v0/clients/rest/models/scheduled_workflows.py +149 -0
  161. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_list.py +110 -0
  162. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_method.py +37 -0
  163. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_order_by_field.py +37 -0
  164. hatchet_sdk/v0/clients/rest/models/semaphore_slots.py +113 -0
  165. hatchet_sdk/v0/clients/rest/models/slack_webhook.py +127 -0
  166. hatchet_sdk/v0/clients/rest/models/sns_integration.py +114 -0
  167. hatchet_sdk/v0/clients/rest/models/step.py +123 -0
  168. hatchet_sdk/v0/clients/rest/models/step_run.py +202 -0
  169. hatchet_sdk/v0/clients/rest/models/step_run_archive.py +142 -0
  170. hatchet_sdk/v0/clients/rest/models/step_run_archive_list.py +110 -0
  171. hatchet_sdk/v0/clients/rest/models/step_run_diff.py +91 -0
  172. hatchet_sdk/v0/clients/rest/models/step_run_event.py +122 -0
  173. hatchet_sdk/v0/clients/rest/models/step_run_event_list.py +110 -0
  174. hatchet_sdk/v0/clients/rest/models/step_run_event_reason.py +52 -0
  175. hatchet_sdk/v0/clients/rest/models/step_run_event_severity.py +38 -0
  176. hatchet_sdk/v0/clients/rest/models/step_run_status.py +44 -0
  177. hatchet_sdk/v0/clients/rest/models/tenant.py +118 -0
  178. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group.py +98 -0
  179. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group_list.py +112 -0
  180. hatchet_sdk/v0/clients/rest/models/tenant_alerting_settings.py +143 -0
  181. hatchet_sdk/v0/clients/rest/models/tenant_invite.py +120 -0
  182. hatchet_sdk/v0/clients/rest/models/tenant_invite_list.py +110 -0
  183. hatchet_sdk/v0/clients/rest/models/tenant_list.py +110 -0
  184. hatchet_sdk/v0/clients/rest/models/tenant_member.py +123 -0
  185. hatchet_sdk/v0/clients/rest/models/tenant_member_list.py +110 -0
  186. hatchet_sdk/v0/clients/rest/models/tenant_member_role.py +38 -0
  187. hatchet_sdk/v0/clients/rest/models/tenant_queue_metrics.py +116 -0
  188. hatchet_sdk/v0/clients/rest/models/tenant_resource.py +40 -0
  189. hatchet_sdk/v0/clients/rest/models/tenant_resource_limit.py +135 -0
  190. hatchet_sdk/v0/clients/rest/models/tenant_resource_policy.py +102 -0
  191. hatchet_sdk/v0/clients/rest/models/tenant_step_run_queue_metrics.py +83 -0
  192. hatchet_sdk/v0/clients/rest/models/trigger_workflow_run_request.py +91 -0
  193. hatchet_sdk/v0/clients/rest/models/update_tenant_alert_email_group_request.py +83 -0
  194. hatchet_sdk/v0/clients/rest/models/update_tenant_invite_request.py +85 -0
  195. hatchet_sdk/v0/clients/rest/models/update_tenant_request.py +137 -0
  196. hatchet_sdk/v0/clients/rest/models/update_worker_request.py +87 -0
  197. hatchet_sdk/v0/clients/rest/models/user.py +126 -0
  198. hatchet_sdk/v0/clients/rest/models/user_change_password_request.py +88 -0
  199. hatchet_sdk/v0/clients/rest/models/user_login_request.py +86 -0
  200. hatchet_sdk/v0/clients/rest/models/user_register_request.py +91 -0
  201. hatchet_sdk/v0/clients/rest/models/user_tenant_memberships_list.py +110 -0
  202. hatchet_sdk/v0/clients/rest/models/user_tenant_public.py +86 -0
  203. hatchet_sdk/v0/clients/rest/models/webhook_worker.py +100 -0
  204. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_request.py +94 -0
  205. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_response.py +98 -0
  206. hatchet_sdk/v0/clients/rest/models/webhook_worker_created.py +102 -0
  207. hatchet_sdk/v0/clients/rest/models/webhook_worker_list_response.py +110 -0
  208. hatchet_sdk/v0/clients/rest/models/webhook_worker_request.py +102 -0
  209. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_list_response.py +104 -0
  210. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_method.py +38 -0
  211. hatchet_sdk/v0/clients/rest/models/worker.py +239 -0
  212. hatchet_sdk/v0/clients/rest/models/worker_label.py +102 -0
  213. hatchet_sdk/v0/clients/rest/models/worker_list.py +110 -0
  214. hatchet_sdk/v0/clients/rest/models/worker_runtime_info.py +103 -0
  215. hatchet_sdk/v0/clients/rest/models/worker_runtime_sdks.py +38 -0
  216. hatchet_sdk/v0/clients/rest/models/worker_type.py +38 -0
  217. hatchet_sdk/v0/clients/rest/models/workflow.py +165 -0
  218. hatchet_sdk/v0/clients/rest/models/workflow_concurrency.py +107 -0
  219. hatchet_sdk/v0/clients/rest/models/workflow_deployment_config.py +136 -0
  220. hatchet_sdk/v0/clients/rest/models/workflow_kind.py +38 -0
  221. hatchet_sdk/v0/clients/rest/models/workflow_list.py +120 -0
  222. hatchet_sdk/v0/clients/rest/models/workflow_metrics.py +97 -0
  223. hatchet_sdk/v0/clients/rest/models/workflow_run.py +188 -0
  224. hatchet_sdk/v0/clients/rest/models/workflow_run_cancel200_response.py +85 -0
  225. hatchet_sdk/v0/clients/rest/models/workflow_run_list.py +110 -0
  226. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_direction.py +37 -0
  227. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_field.py +39 -0
  228. hatchet_sdk/v0/clients/rest/models/workflow_run_shape.py +186 -0
  229. hatchet_sdk/v0/clients/rest/models/workflow_run_status.py +42 -0
  230. hatchet_sdk/v0/clients/rest/models/workflow_run_triggered_by.py +112 -0
  231. hatchet_sdk/v0/clients/rest/models/workflow_runs_cancel_request.py +85 -0
  232. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics.py +94 -0
  233. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics_counts.py +104 -0
  234. hatchet_sdk/v0/clients/rest/models/workflow_tag.py +84 -0
  235. hatchet_sdk/v0/clients/rest/models/workflow_trigger_cron_ref.py +86 -0
  236. hatchet_sdk/v0/clients/rest/models/workflow_trigger_event_ref.py +86 -0
  237. hatchet_sdk/v0/clients/rest/models/workflow_triggers.py +141 -0
  238. hatchet_sdk/v0/clients/rest/models/workflow_update_request.py +85 -0
  239. hatchet_sdk/v0/clients/rest/models/workflow_version.py +170 -0
  240. hatchet_sdk/v0/clients/rest/models/workflow_version_concurrency.py +114 -0
  241. hatchet_sdk/v0/clients/rest/models/workflow_version_definition.py +85 -0
  242. hatchet_sdk/v0/clients/rest/models/workflow_version_meta.py +123 -0
  243. hatchet_sdk/v0/clients/rest/models/workflow_workers_count.py +95 -0
  244. hatchet_sdk/v0/clients/rest/rest.py +187 -0
  245. hatchet_sdk/v0/clients/rest/tenacity_utils.py +39 -0
  246. hatchet_sdk/v0/clients/rest_client.py +613 -0
  247. hatchet_sdk/v0/clients/run_event_listener.py +260 -0
  248. hatchet_sdk/v0/clients/workflow_listener.py +277 -0
  249. hatchet_sdk/v0/connection.py +63 -0
  250. hatchet_sdk/v0/context/__init__.py +1 -0
  251. hatchet_sdk/v0/context/context.py +446 -0
  252. hatchet_sdk/v0/context/worker_context.py +28 -0
  253. hatchet_sdk/v0/contracts/dispatcher_pb2.py +102 -0
  254. hatchet_sdk/v0/contracts/dispatcher_pb2.pyi +387 -0
  255. hatchet_sdk/v0/contracts/dispatcher_pb2_grpc.py +621 -0
  256. hatchet_sdk/v0/contracts/events_pb2.py +46 -0
  257. hatchet_sdk/v0/contracts/events_pb2.pyi +87 -0
  258. hatchet_sdk/v0/contracts/events_pb2_grpc.py +274 -0
  259. hatchet_sdk/v0/contracts/workflows_pb2.py +80 -0
  260. hatchet_sdk/v0/contracts/workflows_pb2.pyi +312 -0
  261. hatchet_sdk/v0/contracts/workflows_pb2_grpc.py +277 -0
  262. hatchet_sdk/v0/features/cron.py +286 -0
  263. hatchet_sdk/v0/features/scheduled.py +248 -0
  264. hatchet_sdk/v0/hatchet.py +310 -0
  265. hatchet_sdk/v0/labels.py +10 -0
  266. hatchet_sdk/v0/logger.py +13 -0
  267. hatchet_sdk/v0/metadata.py +2 -0
  268. hatchet_sdk/v0/opentelemetry/instrumentor.py +396 -0
  269. hatchet_sdk/v0/rate_limit.py +126 -0
  270. hatchet_sdk/v0/semver.py +30 -0
  271. hatchet_sdk/v0/token.py +27 -0
  272. hatchet_sdk/v0/utils/aio_utils.py +137 -0
  273. hatchet_sdk/v0/utils/backoff.py +9 -0
  274. hatchet_sdk/v0/utils/typing.py +12 -0
  275. hatchet_sdk/{v2 → v0/v2}/callable.py +8 -8
  276. hatchet_sdk/{v2 → v0/v2}/concurrency.py +2 -2
  277. hatchet_sdk/{v2 → v0/v2}/hatchet.py +10 -10
  278. hatchet_sdk/v0/worker/__init__.py +1 -0
  279. hatchet_sdk/v0/worker/action_listener_process.py +278 -0
  280. hatchet_sdk/v0/worker/runner/run_loop_manager.py +112 -0
  281. hatchet_sdk/v0/worker/runner/runner.py +460 -0
  282. hatchet_sdk/v0/worker/runner/utils/capture_logs.py +81 -0
  283. hatchet_sdk/v0/worker/runner/utils/error_with_traceback.py +6 -0
  284. hatchet_sdk/v0/worker/worker.py +391 -0
  285. hatchet_sdk/v0/workflow.py +261 -0
  286. hatchet_sdk/v0/workflow_run.py +59 -0
  287. hatchet_sdk/worker/__init__.py +0 -1
  288. hatchet_sdk/worker/action_listener_process.py +36 -33
  289. hatchet_sdk/worker/runner/run_loop_manager.py +18 -16
  290. hatchet_sdk/worker/runner/runner.py +32 -60
  291. hatchet_sdk/worker/runner/utils/capture_logs.py +25 -14
  292. hatchet_sdk/worker/runner/utils/error_with_traceback.py +1 -1
  293. hatchet_sdk/worker/worker.py +61 -75
  294. hatchet_sdk/workflow.py +473 -207
  295. hatchet_sdk/workflow_run.py +5 -18
  296. {hatchet_sdk-0.47.0.dist-info → hatchet_sdk-1.0.0.dist-info}/METADATA +2 -1
  297. hatchet_sdk-1.0.0.dist-info/RECORD +485 -0
  298. hatchet_sdk/utils/serialization.py +0 -18
  299. hatchet_sdk-0.47.0.dist-info/RECORD +0 -237
  300. /hatchet_sdk/{loader.py → v0/loader.py} +0 -0
  301. /hatchet_sdk/{utils → v0/utils}/types.py +0 -0
  302. {hatchet_sdk-0.47.0.dist-info → hatchet_sdk-1.0.0.dist-info}/WHEEL +0 -0
  303. {hatchet_sdk-0.47.0.dist-info → hatchet_sdk-1.0.0.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,12 @@
1
1
  import asyncio
2
2
  import json
3
- from typing import AsyncGenerator
3
+ from enum import Enum
4
+ from typing import Any, AsyncGenerator, Callable, Generator, cast
4
5
 
5
6
  import grpc
7
+ from pydantic import BaseModel
6
8
 
9
+ from hatchet_sdk.config import ClientConfig
7
10
  from hatchet_sdk.connection import new_conn
8
11
  from hatchet_sdk.contracts.dispatcher_pb2 import (
9
12
  RESOURCE_TYPE_STEP_RUN,
@@ -13,15 +16,13 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
13
16
  WorkflowEvent,
14
17
  )
15
18
  from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
16
-
17
- from ..loader import ClientConfig
18
- from ..metadata import get_metadata
19
+ from hatchet_sdk.metadata import get_metadata
19
20
 
20
21
  DEFAULT_ACTION_LISTENER_RETRY_INTERVAL = 5 # seconds
21
22
  DEFAULT_ACTION_LISTENER_RETRY_COUNT = 5
22
23
 
23
24
 
24
- class StepRunEventType:
25
+ class StepRunEventType(str, Enum):
25
26
  STEP_RUN_EVENT_TYPE_STARTED = "STEP_RUN_EVENT_TYPE_STARTED"
26
27
  STEP_RUN_EVENT_TYPE_COMPLETED = "STEP_RUN_EVENT_TYPE_COMPLETED"
27
28
  STEP_RUN_EVENT_TYPE_FAILED = "STEP_RUN_EVENT_TYPE_FAILED"
@@ -30,7 +31,7 @@ class StepRunEventType:
30
31
  STEP_RUN_EVENT_TYPE_STREAM = "STEP_RUN_EVENT_TYPE_STREAM"
31
32
 
32
33
 
33
- class WorkflowRunEventType:
34
+ class WorkflowRunEventType(str, Enum):
34
35
  WORKFLOW_RUN_EVENT_TYPE_STARTED = "WORKFLOW_RUN_EVENT_TYPE_STARTED"
35
36
  WORKFLOW_RUN_EVENT_TYPE_COMPLETED = "WORKFLOW_RUN_EVENT_TYPE_COMPLETED"
36
37
  WORKFLOW_RUN_EVENT_TYPE_FAILED = "WORKFLOW_RUN_EVENT_TYPE_FAILED"
@@ -56,50 +57,36 @@ workflow_run_event_type_mapping = {
56
57
  }
57
58
 
58
59
 
59
- class StepRunEvent:
60
- def __init__(self, type: StepRunEventType, payload: str):
61
- self.type = type
62
- self.payload = payload
63
-
64
-
65
- def new_listener(config: ClientConfig):
66
- return RunEventListenerClient(config=config)
60
+ class StepRunEvent(BaseModel):
61
+ type: StepRunEventType
62
+ payload: str
67
63
 
68
64
 
69
65
  class RunEventListener:
70
-
71
- workflow_run_id: str = None
72
- additional_meta_kv: tuple[str, str] = None
73
-
74
- def __init__(self, client: DispatcherStub, token: str):
66
+ def __init__(
67
+ self,
68
+ client: DispatcherStub,
69
+ token: str,
70
+ workflow_run_id: str | None = None,
71
+ additional_meta_kv: tuple[str, str] | None = None,
72
+ ):
75
73
  self.client = client
76
74
  self.stop_signal = False
77
75
  self.token = token
78
76
 
79
- @classmethod
80
- def for_run_id(cls, workflow_run_id: str, client: DispatcherStub, token: str):
81
- listener = RunEventListener(client, token)
82
- listener.workflow_run_id = workflow_run_id
83
- return listener
77
+ self.workflow_run_id = workflow_run_id
78
+ self.additional_meta_kv = additional_meta_kv
84
79
 
85
- @classmethod
86
- def for_additional_meta(
87
- cls, key: str, value: str, client: DispatcherStub, token: str
88
- ):
89
- listener = RunEventListener(client, token)
90
- listener.additional_meta_kv = (key, value)
91
- return listener
92
-
93
- def abort(self):
80
+ def abort(self) -> None:
94
81
  self.stop_signal = True
95
82
 
96
- def __aiter__(self):
83
+ def __aiter__(self) -> AsyncGenerator[StepRunEvent, None]:
97
84
  return self._generator()
98
85
 
99
- async def __anext__(self):
86
+ async def __anext__(self) -> StepRunEvent:
100
87
  return await self._generator().__anext__()
101
88
 
102
- def __iter__(self):
89
+ def __iter__(self) -> Generator[StepRunEvent, None, None]:
103
90
  try:
104
91
  loop = asyncio.get_event_loop()
105
92
  except RuntimeError as e:
@@ -145,15 +132,18 @@ class RunEventListener:
145
132
 
146
133
  try:
147
134
  if workflow_event.eventPayload:
135
+ ## TODO: Should this be `dumps` instead?
148
136
  payload = json.loads(workflow_event.eventPayload)
149
- except Exception as e:
137
+ except Exception:
150
138
  payload = workflow_event.eventPayload
151
139
  pass
152
140
 
141
+ assert isinstance(payload, str)
142
+
153
143
  yield StepRunEvent(type=eventType, payload=payload)
154
144
  elif workflow_event.resourceType == RESOURCE_TYPE_WORKFLOW_RUN:
155
- if workflow_event.eventType in workflow_run_event_type_mapping:
156
- eventType = workflow_run_event_type_mapping[
145
+ if workflow_event.eventType in step_run_event_type_mapping:
146
+ workflowRunEventType = step_run_event_type_mapping[
157
147
  workflow_event.eventType
158
148
  ]
159
149
  else:
@@ -166,10 +156,12 @@ class RunEventListener:
166
156
  try:
167
157
  if workflow_event.eventPayload:
168
158
  payload = json.loads(workflow_event.eventPayload)
169
- except Exception as e:
159
+ except Exception:
170
160
  pass
171
161
 
172
- yield StepRunEvent(type=eventType, payload=payload)
162
+ assert isinstance(payload, str)
163
+
164
+ yield StepRunEvent(type=workflowRunEventType, payload=payload)
173
165
 
174
166
  if workflow_event.hangup:
175
167
  listener = None
@@ -194,7 +186,7 @@ class RunEventListener:
194
186
  break
195
187
  # Raise StopAsyncIteration to properly end the generator
196
188
 
197
- async def retry_subscribe(self):
189
+ async def retry_subscribe(self) -> AsyncGenerator[WorkflowEvent, None]:
198
190
  retries = 0
199
191
 
200
192
  while retries < DEFAULT_ACTION_LISTENER_RETRY_COUNT:
@@ -203,19 +195,25 @@ class RunEventListener:
203
195
  await asyncio.sleep(DEFAULT_ACTION_LISTENER_RETRY_INTERVAL)
204
196
 
205
197
  if self.workflow_run_id is not None:
206
- return self.client.SubscribeToWorkflowEvents(
207
- SubscribeToWorkflowEventsRequest(
208
- workflowRunId=self.workflow_run_id,
198
+ return cast(
199
+ AsyncGenerator[WorkflowEvent, None],
200
+ self.client.SubscribeToWorkflowEvents(
201
+ SubscribeToWorkflowEventsRequest(
202
+ workflowRunId=self.workflow_run_id,
203
+ ),
204
+ metadata=get_metadata(self.token),
209
205
  ),
210
- metadata=get_metadata(self.token),
211
206
  )
212
207
  elif self.additional_meta_kv is not None:
213
- return self.client.SubscribeToWorkflowEvents(
214
- SubscribeToWorkflowEventsRequest(
215
- additionalMetaKey=self.additional_meta_kv[0],
216
- additionalMetaValue=self.additional_meta_kv[1],
208
+ return cast(
209
+ AsyncGenerator[WorkflowEvent, None],
210
+ self.client.SubscribeToWorkflowEvents(
211
+ SubscribeToWorkflowEventsRequest(
212
+ additionalMetaKey=self.additional_meta_kv[0],
213
+ additionalMetaValue=self.additional_meta_kv[1],
214
+ ),
215
+ metadata=get_metadata(self.token),
217
216
  ),
218
- metadata=get_metadata(self.token),
219
217
  )
220
218
  else:
221
219
  raise Exception("no listener method provided")
@@ -226,34 +224,42 @@ class RunEventListener:
226
224
  else:
227
225
  raise ValueError(f"gRPC error: {e}")
228
226
 
227
+ raise Exception("Failed to subscribe to workflow events")
228
+
229
229
 
230
230
  class RunEventListenerClient:
231
231
  def __init__(self, config: ClientConfig):
232
232
  self.token = config.token
233
233
  self.config = config
234
- self.client: DispatcherStub = None
234
+ self.client: DispatcherStub | None = None
235
235
 
236
- def stream_by_run_id(self, workflow_run_id: str):
236
+ def stream_by_run_id(self, workflow_run_id: str) -> RunEventListener:
237
237
  return self.stream(workflow_run_id)
238
238
 
239
- def stream(self, workflow_run_id: str):
239
+ def stream(self, workflow_run_id: str) -> RunEventListener:
240
240
  if not isinstance(workflow_run_id, str) and hasattr(workflow_run_id, "__str__"):
241
241
  workflow_run_id = str(workflow_run_id)
242
242
 
243
243
  if not self.client:
244
244
  aio_conn = new_conn(self.config, True)
245
- self.client = DispatcherStub(aio_conn)
245
+ self.client = DispatcherStub(aio_conn) # type: ignore[no-untyped-call]
246
246
 
247
- return RunEventListener.for_run_id(workflow_run_id, self.client, self.token)
247
+ return RunEventListener(
248
+ client=self.client, token=self.token, workflow_run_id=workflow_run_id
249
+ )
248
250
 
249
- def stream_by_additional_metadata(self, key: str, value: str):
251
+ def stream_by_additional_metadata(self, key: str, value: str) -> RunEventListener:
250
252
  if not self.client:
251
253
  aio_conn = new_conn(self.config, True)
252
- self.client = DispatcherStub(aio_conn)
254
+ self.client = DispatcherStub(aio_conn) # type: ignore[no-untyped-call]
253
255
 
254
- return RunEventListener.for_additional_meta(key, value, self.client, self.token)
256
+ return RunEventListener(
257
+ client=self.client, token=self.token, additional_meta_kv=(key, value)
258
+ )
255
259
 
256
- async def on(self, workflow_run_id: str, handler: callable = None):
260
+ async def on(
261
+ self, workflow_run_id: str, handler: Callable[[StepRunEvent], Any] | None = None
262
+ ) -> None:
257
263
  async for event in self.stream(workflow_run_id):
258
264
  # call the handler if provided
259
265
  if handler:
@@ -1,22 +1,22 @@
1
1
  import asyncio
2
2
  import json
3
3
  from collections.abc import AsyncIterator
4
- from typing import AsyncGenerator
4
+ from typing import Any, cast
5
5
 
6
6
  import grpc
7
- from grpc._cython import cygrpc
7
+ import grpc.aio
8
+ from grpc._cython import cygrpc # type: ignore[attr-defined]
8
9
 
9
- from hatchet_sdk.clients.event_ts import Event_ts, read_with_interrupt
10
+ from hatchet_sdk.clients.event_ts import ThreadSafeEvent, read_with_interrupt
11
+ from hatchet_sdk.config import ClientConfig
10
12
  from hatchet_sdk.connection import new_conn
11
13
  from hatchet_sdk.contracts.dispatcher_pb2 import (
12
14
  SubscribeToWorkflowRunsRequest,
13
15
  WorkflowRunEvent,
14
16
  )
15
17
  from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
16
-
17
- from ..loader import ClientConfig
18
- from ..logger import logger
19
- from ..metadata import get_metadata
18
+ from hatchet_sdk.logger import logger
19
+ from hatchet_sdk.metadata import get_metadata
20
20
 
21
21
  DEFAULT_WORKFLOW_LISTENER_RETRY_INTERVAL = 3 # seconds
22
22
  DEFAULT_WORKFLOW_LISTENER_RETRY_COUNT = 5
@@ -31,10 +31,10 @@ class _Subscription:
31
31
  self.workflow_run_id = workflow_run_id
32
32
  self.queue: asyncio.Queue[WorkflowRunEvent | None] = asyncio.Queue()
33
33
 
34
- async def __aiter__(self):
34
+ async def __aiter__(self) -> "_Subscription":
35
35
  return self
36
36
 
37
- async def __anext__(self) -> WorkflowRunEvent:
37
+ async def __anext__(self) -> WorkflowRunEvent | None:
38
38
  return await self.queue.get()
39
39
 
40
40
  async def get(self) -> WorkflowRunEvent:
@@ -45,35 +45,14 @@ class _Subscription:
45
45
 
46
46
  return event
47
47
 
48
- async def put(self, item: WorkflowRunEvent):
48
+ async def put(self, item: WorkflowRunEvent) -> None:
49
49
  await self.queue.put(item)
50
50
 
51
- async def close(self):
51
+ async def close(self) -> None:
52
52
  await self.queue.put(None)
53
53
 
54
54
 
55
55
  class PooledWorkflowRunListener:
56
- # list of all active subscriptions, mapping from a subscription id to a workflow run id
57
- subscriptionsToWorkflows: dict[int, str] = {}
58
-
59
- # list of workflow run ids mapped to an array of subscription ids
60
- workflowsToSubscriptions: dict[str, list[int]] = {}
61
-
62
- subscription_counter: int = 0
63
- subscription_counter_lock: asyncio.Lock = asyncio.Lock()
64
-
65
- requests: asyncio.Queue[SubscribeToWorkflowRunsRequest] = asyncio.Queue()
66
-
67
- listener: AsyncGenerator[WorkflowRunEvent, None] = None
68
- listener_task: asyncio.Task = None
69
-
70
- curr_requester: int = 0
71
-
72
- # events have keys of the format workflow_run_id + subscription_id
73
- events: dict[int, _Subscription] = {}
74
-
75
- interrupter: asyncio.Task = None
76
-
77
56
  def __init__(self, config: ClientConfig):
78
57
  try:
79
58
  asyncio.get_running_loop()
@@ -82,11 +61,37 @@ class PooledWorkflowRunListener:
82
61
  asyncio.set_event_loop(loop)
83
62
 
84
63
  conn = new_conn(config, True)
85
- self.client = DispatcherStub(conn)
64
+ self.client = DispatcherStub(conn) # type: ignore[no-untyped-call]
86
65
  self.token = config.token
87
66
  self.config = config
88
67
 
89
- async def _interrupter(self):
68
+ # list of all active subscriptions, mapping from a subscription id to a workflow run id
69
+ self.subscriptions_to_workflows: dict[int, str] = {}
70
+
71
+ # list of workflow run ids mapped to an array of subscription ids
72
+ self.workflows_to_subscriptions: dict[str, list[int]] = {}
73
+
74
+ self.subscription_counter: int = 0
75
+ self.subscription_counter_lock: asyncio.Lock = asyncio.Lock()
76
+
77
+ self.requests: asyncio.Queue[SubscribeToWorkflowRunsRequest | int] = (
78
+ asyncio.Queue()
79
+ )
80
+
81
+ self.listener: (
82
+ grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]
83
+ | None
84
+ ) = None
85
+ self.listener_task: asyncio.Task[None] | None = None
86
+
87
+ self.curr_requester: int = 0
88
+
89
+ # events have keys of the format workflow_run_id + subscription_id
90
+ self.events: dict[int, _Subscription] = {}
91
+
92
+ self.interrupter: asyncio.Task[None] | None = None
93
+
94
+ async def _interrupter(self) -> None:
90
95
  """
91
96
  _interrupter runs in a separate thread and interrupts the listener according to a configurable duration.
92
97
  """
@@ -95,7 +100,7 @@ class PooledWorkflowRunListener:
95
100
  if self.interrupt is not None:
96
101
  self.interrupt.set()
97
102
 
98
- async def _init_producer(self):
103
+ async def _init_producer(self) -> None:
99
104
  try:
100
105
  if not self.listener:
101
106
  while True:
@@ -111,7 +116,10 @@ class PooledWorkflowRunListener:
111
116
  self.interrupter = asyncio.create_task(self._interrupter())
112
117
 
113
118
  while True:
114
- self.interrupt = Event_ts()
119
+ self.interrupt = ThreadSafeEvent()
120
+ if self.listener is None:
121
+ continue
122
+
115
123
  t = asyncio.create_task(
116
124
  read_with_interrupt(self.listener, self.interrupt)
117
125
  )
@@ -124,7 +132,8 @@ class PooledWorkflowRunListener:
124
132
  )
125
133
 
126
134
  t.cancel()
127
- self.listener.cancel()
135
+ if self.listener:
136
+ self.listener.cancel()
128
137
  await asyncio.sleep(
129
138
  DEFAULT_WORKFLOW_LISTENER_RETRY_INTERVAL
130
139
  )
@@ -136,7 +145,7 @@ class PooledWorkflowRunListener:
136
145
  break
137
146
 
138
147
  # get a list of subscriptions for this workflow
139
- subscriptions = self.workflowsToSubscriptions.get(
148
+ subscriptions = self.workflows_to_subscriptions.get(
140
149
  workflow_event.workflowRunId, []
141
150
  )
142
151
 
@@ -163,7 +172,7 @@ class PooledWorkflowRunListener:
163
172
  self.curr_requester = self.curr_requester + 1
164
173
 
165
174
  # replay all existing subscriptions
166
- workflow_run_set = set(self.subscriptionsToWorkflows.values())
175
+ workflow_run_set = set(self.subscriptions_to_workflows.values())
167
176
 
168
177
  for workflow_run_id in workflow_run_set:
169
178
  yield SubscribeToWorkflowRunsRequest(
@@ -184,17 +193,16 @@ class PooledWorkflowRunListener:
184
193
  yield request
185
194
  self.requests.task_done()
186
195
 
187
- def cleanup_subscription(self, subscription_id: int):
188
- workflow_run_id = self.subscriptionsToWorkflows[subscription_id]
196
+ def cleanup_subscription(self, subscription_id: int) -> None:
197
+ workflow_run_id = self.subscriptions_to_workflows[subscription_id]
189
198
 
190
- if workflow_run_id in self.workflowsToSubscriptions:
191
- self.workflowsToSubscriptions[workflow_run_id].remove(subscription_id)
199
+ if workflow_run_id in self.workflows_to_subscriptions:
200
+ self.workflows_to_subscriptions[workflow_run_id].remove(subscription_id)
192
201
 
193
- del self.subscriptionsToWorkflows[subscription_id]
202
+ del self.subscriptions_to_workflows[subscription_id]
194
203
  del self.events[subscription_id]
195
204
 
196
- async def subscribe(self, workflow_run_id: str):
197
- init_producer: asyncio.Task = None
205
+ async def subscribe(self, workflow_run_id: str) -> WorkflowRunEvent:
198
206
  try:
199
207
  # create a new subscription id, place a mutex on the counter
200
208
  await self.subscription_counter_lock.acquire()
@@ -202,12 +210,12 @@ class PooledWorkflowRunListener:
202
210
  subscription_id = self.subscription_counter
203
211
  self.subscription_counter_lock.release()
204
212
 
205
- self.subscriptionsToWorkflows[subscription_id] = workflow_run_id
213
+ self.subscriptions_to_workflows[subscription_id] = workflow_run_id
206
214
 
207
- if workflow_run_id not in self.workflowsToSubscriptions:
208
- self.workflowsToSubscriptions[workflow_run_id] = [subscription_id]
215
+ if workflow_run_id not in self.workflows_to_subscriptions:
216
+ self.workflows_to_subscriptions[workflow_run_id] = [subscription_id]
209
217
  else:
210
- self.workflowsToSubscriptions[workflow_run_id].append(subscription_id)
218
+ self.workflows_to_subscriptions[workflow_run_id].append(subscription_id)
211
219
 
212
220
  self.events[subscription_id] = _Subscription(
213
221
  subscription_id, workflow_run_id
@@ -222,23 +230,17 @@ class PooledWorkflowRunListener:
222
230
  if not self.listener_task or self.listener_task.done():
223
231
  self.listener_task = asyncio.create_task(self._init_producer())
224
232
 
225
- event = await self.events[subscription_id].get()
226
-
227
- return event
233
+ return await self.events[subscription_id].get()
228
234
  except asyncio.CancelledError:
229
235
  raise
230
236
  finally:
231
237
  self.cleanup_subscription(subscription_id)
232
238
 
233
- async def result(self, workflow_run_id: str):
239
+ async def result(self, workflow_run_id: str) -> dict[str, Any]:
234
240
  from hatchet_sdk.clients.admin import DedupeViolationErr
235
241
 
236
242
  event = await self.subscribe(workflow_run_id)
237
-
238
- errors = []
239
-
240
- if event.results:
241
- errors = [result.error for result in event.results if result.error]
243
+ errors = [result.error for result in event.results if result.error]
242
244
 
243
245
  if errors:
244
246
  if DEDUPE_MESSAGE in errors[0]:
@@ -246,15 +248,15 @@ class PooledWorkflowRunListener:
246
248
  else:
247
249
  raise Exception(f"Workflow Errors: {errors}")
248
250
 
249
- results = {
251
+ return {
250
252
  result.stepReadableId: json.loads(result.output)
251
253
  for result in event.results
252
254
  if result.output
253
255
  }
254
256
 
255
- return results
256
-
257
- async def _retry_subscribe(self):
257
+ async def _retry_subscribe(
258
+ self,
259
+ ) -> grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]:
258
260
  retries = 0
259
261
 
260
262
  while retries < DEFAULT_WORKFLOW_LISTENER_RETRY_COUNT:
@@ -266,12 +268,19 @@ class PooledWorkflowRunListener:
266
268
  if self.curr_requester != 0:
267
269
  self.requests.put_nowait(self.curr_requester)
268
270
 
269
- return self.client.SubscribeToWorkflowRuns(
270
- self._request(),
271
- metadata=get_metadata(self.token),
271
+ return cast(
272
+ grpc.aio.UnaryStreamCall[
273
+ SubscribeToWorkflowRunsRequest, WorkflowRunEvent
274
+ ],
275
+ self.client.SubscribeToWorkflowRuns(
276
+ self._request(),
277
+ metadata=get_metadata(self.token),
278
+ ),
272
279
  )
273
280
  except grpc.RpcError as e:
274
281
  if e.code() == grpc.StatusCode.UNAVAILABLE:
275
282
  retries = retries + 1
276
283
  else:
277
284
  raise ValueError(f"gRPC error: {e}")
285
+
286
+ raise ValueError("Failed to connect to workflow run listener")
hatchet_sdk/config.py ADDED
@@ -0,0 +1,117 @@
1
+ import json
2
+ from logging import Logger, getLogger
3
+
4
+ from pydantic import Field, field_validator, model_validator
5
+ from pydantic_settings import BaseSettings, SettingsConfigDict
6
+
7
+ from hatchet_sdk.token import get_addresses_from_jwt, get_tenant_id_from_jwt
8
+
9
+
10
+ def create_settings_config(env_prefix: str) -> SettingsConfigDict:
11
+ return SettingsConfigDict(
12
+ env_prefix=env_prefix,
13
+ env_file=(".env", ".env.hatchet", ".env.dev", ".env.local"),
14
+ extra="ignore",
15
+ )
16
+
17
+
18
+ class ClientTLSConfig(BaseSettings):
19
+ model_config = create_settings_config(
20
+ env_prefix="HATCHET_CLIENT_TLS_",
21
+ )
22
+
23
+ strategy: str = "tls"
24
+ cert_file: str | None = None
25
+ key_file: str | None = None
26
+ root_ca_file: str | None = None
27
+ server_name: str = ""
28
+
29
+
30
+ class HealthcheckConfig(BaseSettings):
31
+ model_config = create_settings_config(
32
+ env_prefix="HATCHET_CLIENT_WORKER_HEALTHCHECK_",
33
+ )
34
+
35
+ port: int = 8001
36
+ enabled: bool = False
37
+
38
+
39
+ DEFAULT_HOST_PORT = "localhost:7070"
40
+
41
+
42
+ class ClientConfig(BaseSettings):
43
+ model_config = create_settings_config(
44
+ env_prefix="HATCHET_CLIENT_",
45
+ )
46
+
47
+ token: str = ""
48
+ logger: Logger = getLogger()
49
+
50
+ tenant_id: str = ""
51
+ host_port: str = DEFAULT_HOST_PORT
52
+ server_url: str = "https://app.dev.hatchet-tools.com"
53
+ namespace: str = ""
54
+
55
+ tls_config: ClientTLSConfig = Field(default_factory=lambda: ClientTLSConfig())
56
+ healthcheck: HealthcheckConfig = Field(default_factory=lambda: HealthcheckConfig())
57
+
58
+ listener_v2_timeout: int | None = None
59
+ grpc_max_recv_message_length: int = Field(
60
+ default=4 * 1024 * 1024, description="4MB default"
61
+ )
62
+ grpc_max_send_message_length: int = Field(
63
+ default=4 * 1024 * 1024, description="4MB default"
64
+ )
65
+
66
+ worker_preset_labels: dict[str, str] = Field(default_factory=dict)
67
+ enable_force_kill_sync_threads: bool = False
68
+
69
+ @model_validator(mode="after")
70
+ def validate_token_and_tenant(self) -> "ClientConfig":
71
+ if not self.token:
72
+ raise ValueError("Token must be set")
73
+
74
+ if not self.tenant_id:
75
+ self.tenant_id = get_tenant_id_from_jwt(self.token)
76
+
77
+ return self
78
+
79
+ @model_validator(mode="after")
80
+ def validate_addresses(self) -> "ClientConfig":
81
+ if self.host_port == DEFAULT_HOST_PORT:
82
+ server_url, grpc_broadcast_address = get_addresses_from_jwt(self.token)
83
+ self.host_port = grpc_broadcast_address
84
+ self.server_url = server_url
85
+ else:
86
+ self.server_url = self.host_port
87
+
88
+ if not self.tls_config.server_name:
89
+ self.tls_config.server_name = self.host_port.split(":")[0]
90
+
91
+ if not self.tls_config.server_name:
92
+ self.tls_config.server_name = "localhost"
93
+
94
+ return self
95
+
96
+ @field_validator("listener_v2_timeout")
97
+ @classmethod
98
+ def validate_listener_timeout(cls, value: int | None | str) -> int | None:
99
+ if value is None:
100
+ return None
101
+
102
+ if isinstance(value, int):
103
+ return value
104
+
105
+ return int(value)
106
+
107
+ @field_validator("namespace")
108
+ @classmethod
109
+ def validate_namespace(cls, namespace: str) -> str:
110
+ if not namespace:
111
+ return ""
112
+ if not namespace.endswith("_"):
113
+ namespace = f"{namespace}_"
114
+ return namespace.lower()
115
+
116
+ def __hash__(self) -> int:
117
+ return hash(json.dumps(self.model_dump(), default=str))