hatchet-sdk 0.46.1__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 +77 -64
  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 +143 -202
  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 +112 -35
  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/{loader.py → v0/loader.py} +11 -0
  267. hatchet_sdk/v0/logger.py +13 -0
  268. hatchet_sdk/v0/metadata.py +2 -0
  269. hatchet_sdk/v0/opentelemetry/instrumentor.py +396 -0
  270. hatchet_sdk/v0/rate_limit.py +126 -0
  271. hatchet_sdk/v0/semver.py +30 -0
  272. hatchet_sdk/v0/token.py +27 -0
  273. hatchet_sdk/v0/utils/aio_utils.py +137 -0
  274. hatchet_sdk/v0/utils/backoff.py +9 -0
  275. hatchet_sdk/v0/utils/typing.py +12 -0
  276. hatchet_sdk/{v2 → v0/v2}/callable.py +8 -8
  277. hatchet_sdk/{v2 → v0/v2}/concurrency.py +2 -2
  278. hatchet_sdk/{v2 → v0/v2}/hatchet.py +10 -10
  279. hatchet_sdk/v0/worker/__init__.py +1 -0
  280. hatchet_sdk/v0/worker/action_listener_process.py +278 -0
  281. hatchet_sdk/v0/worker/runner/run_loop_manager.py +112 -0
  282. hatchet_sdk/v0/worker/runner/runner.py +460 -0
  283. hatchet_sdk/v0/worker/runner/utils/capture_logs.py +81 -0
  284. hatchet_sdk/v0/worker/runner/utils/error_with_traceback.py +6 -0
  285. hatchet_sdk/v0/worker/worker.py +391 -0
  286. hatchet_sdk/v0/workflow.py +261 -0
  287. hatchet_sdk/v0/workflow_run.py +59 -0
  288. hatchet_sdk/worker/__init__.py +0 -1
  289. hatchet_sdk/worker/action_listener_process.py +36 -33
  290. hatchet_sdk/worker/runner/run_loop_manager.py +18 -16
  291. hatchet_sdk/worker/runner/runner.py +37 -59
  292. hatchet_sdk/worker/runner/utils/capture_logs.py +25 -14
  293. hatchet_sdk/worker/runner/utils/error_with_traceback.py +1 -1
  294. hatchet_sdk/worker/worker.py +61 -75
  295. hatchet_sdk/workflow.py +473 -207
  296. hatchet_sdk/workflow_run.py +14 -25
  297. {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/METADATA +3 -2
  298. hatchet_sdk-1.0.0.dist-info/RECORD +485 -0
  299. {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/entry_points.txt +1 -0
  300. hatchet_sdk/utils/serialization.py +0 -18
  301. hatchet_sdk-0.46.1.dist-info/RECORD +0 -237
  302. /hatchet_sdk/{utils → v0/utils}/types.py +0 -0
  303. {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/WHEEL +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,42 +45,53 @@ 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] = {}
56
+ def __init__(self, config: ClientConfig):
57
+ try:
58
+ asyncio.get_running_loop()
59
+ except RuntimeError:
60
+ loop = asyncio.new_event_loop()
61
+ asyncio.set_event_loop(loop)
58
62
 
59
- # list of workflow run ids mapped to an array of subscription ids
60
- workflowsToSubscriptions: dict[str, list[int]] = {}
63
+ conn = new_conn(config, True)
64
+ self.client = DispatcherStub(conn) # type: ignore[no-untyped-call]
65
+ self.token = config.token
66
+ self.config = config
61
67
 
62
- subscription_counter: int = 0
63
- subscription_counter_lock: asyncio.Lock = asyncio.Lock()
68
+ # list of all active subscriptions, mapping from a subscription id to a workflow run id
69
+ self.subscriptions_to_workflows: dict[int, str] = {}
64
70
 
65
- requests: asyncio.Queue[SubscribeToWorkflowRunsRequest] = asyncio.Queue()
71
+ # list of workflow run ids mapped to an array of subscription ids
72
+ self.workflows_to_subscriptions: dict[str, list[int]] = {}
66
73
 
67
- listener: AsyncGenerator[WorkflowRunEvent, None] = None
68
- listener_task: asyncio.Task = None
74
+ self.subscription_counter: int = 0
75
+ self.subscription_counter_lock: asyncio.Lock = asyncio.Lock()
69
76
 
70
- curr_requester: int = 0
77
+ self.requests: asyncio.Queue[SubscribeToWorkflowRunsRequest | int] = (
78
+ asyncio.Queue()
79
+ )
71
80
 
72
- # events have keys of the format workflow_run_id + subscription_id
73
- events: dict[int, _Subscription] = {}
81
+ self.listener: (
82
+ grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]
83
+ | None
84
+ ) = None
85
+ self.listener_task: asyncio.Task[None] | None = None
74
86
 
75
- interrupter: asyncio.Task = None
87
+ self.curr_requester: int = 0
76
88
 
77
- def __init__(self, config: ClientConfig):
78
- conn = new_conn(config, True)
79
- self.client = DispatcherStub(conn)
80
- self.token = config.token
81
- self.config = config
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
82
93
 
83
- async def _interrupter(self):
94
+ async def _interrupter(self) -> None:
84
95
  """
85
96
  _interrupter runs in a separate thread and interrupts the listener according to a configurable duration.
86
97
  """
@@ -89,7 +100,7 @@ class PooledWorkflowRunListener:
89
100
  if self.interrupt is not None:
90
101
  self.interrupt.set()
91
102
 
92
- async def _init_producer(self):
103
+ async def _init_producer(self) -> None:
93
104
  try:
94
105
  if not self.listener:
95
106
  while True:
@@ -105,7 +116,10 @@ class PooledWorkflowRunListener:
105
116
  self.interrupter = asyncio.create_task(self._interrupter())
106
117
 
107
118
  while True:
108
- self.interrupt = Event_ts()
119
+ self.interrupt = ThreadSafeEvent()
120
+ if self.listener is None:
121
+ continue
122
+
109
123
  t = asyncio.create_task(
110
124
  read_with_interrupt(self.listener, self.interrupt)
111
125
  )
@@ -118,7 +132,8 @@ class PooledWorkflowRunListener:
118
132
  )
119
133
 
120
134
  t.cancel()
121
- self.listener.cancel()
135
+ if self.listener:
136
+ self.listener.cancel()
122
137
  await asyncio.sleep(
123
138
  DEFAULT_WORKFLOW_LISTENER_RETRY_INTERVAL
124
139
  )
@@ -130,7 +145,7 @@ class PooledWorkflowRunListener:
130
145
  break
131
146
 
132
147
  # get a list of subscriptions for this workflow
133
- subscriptions = self.workflowsToSubscriptions.get(
148
+ subscriptions = self.workflows_to_subscriptions.get(
134
149
  workflow_event.workflowRunId, []
135
150
  )
136
151
 
@@ -157,7 +172,7 @@ class PooledWorkflowRunListener:
157
172
  self.curr_requester = self.curr_requester + 1
158
173
 
159
174
  # replay all existing subscriptions
160
- workflow_run_set = set(self.subscriptionsToWorkflows.values())
175
+ workflow_run_set = set(self.subscriptions_to_workflows.values())
161
176
 
162
177
  for workflow_run_id in workflow_run_set:
163
178
  yield SubscribeToWorkflowRunsRequest(
@@ -178,17 +193,16 @@ class PooledWorkflowRunListener:
178
193
  yield request
179
194
  self.requests.task_done()
180
195
 
181
- def cleanup_subscription(self, subscription_id: int):
182
- 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]
183
198
 
184
- if workflow_run_id in self.workflowsToSubscriptions:
185
- 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)
186
201
 
187
- del self.subscriptionsToWorkflows[subscription_id]
202
+ del self.subscriptions_to_workflows[subscription_id]
188
203
  del self.events[subscription_id]
189
204
 
190
- async def subscribe(self, workflow_run_id: str):
191
- init_producer: asyncio.Task = None
205
+ async def subscribe(self, workflow_run_id: str) -> WorkflowRunEvent:
192
206
  try:
193
207
  # create a new subscription id, place a mutex on the counter
194
208
  await self.subscription_counter_lock.acquire()
@@ -196,12 +210,12 @@ class PooledWorkflowRunListener:
196
210
  subscription_id = self.subscription_counter
197
211
  self.subscription_counter_lock.release()
198
212
 
199
- self.subscriptionsToWorkflows[subscription_id] = workflow_run_id
213
+ self.subscriptions_to_workflows[subscription_id] = workflow_run_id
200
214
 
201
- if workflow_run_id not in self.workflowsToSubscriptions:
202
- 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]
203
217
  else:
204
- self.workflowsToSubscriptions[workflow_run_id].append(subscription_id)
218
+ self.workflows_to_subscriptions[workflow_run_id].append(subscription_id)
205
219
 
206
220
  self.events[subscription_id] = _Subscription(
207
221
  subscription_id, workflow_run_id
@@ -216,23 +230,17 @@ class PooledWorkflowRunListener:
216
230
  if not self.listener_task or self.listener_task.done():
217
231
  self.listener_task = asyncio.create_task(self._init_producer())
218
232
 
219
- event = await self.events[subscription_id].get()
220
-
221
- return event
233
+ return await self.events[subscription_id].get()
222
234
  except asyncio.CancelledError:
223
235
  raise
224
236
  finally:
225
237
  self.cleanup_subscription(subscription_id)
226
238
 
227
- async def result(self, workflow_run_id: str):
239
+ async def result(self, workflow_run_id: str) -> dict[str, Any]:
228
240
  from hatchet_sdk.clients.admin import DedupeViolationErr
229
241
 
230
242
  event = await self.subscribe(workflow_run_id)
231
-
232
- errors = []
233
-
234
- if event.results:
235
- errors = [result.error for result in event.results if result.error]
243
+ errors = [result.error for result in event.results if result.error]
236
244
 
237
245
  if errors:
238
246
  if DEDUPE_MESSAGE in errors[0]:
@@ -240,15 +248,15 @@ class PooledWorkflowRunListener:
240
248
  else:
241
249
  raise Exception(f"Workflow Errors: {errors}")
242
250
 
243
- results = {
251
+ return {
244
252
  result.stepReadableId: json.loads(result.output)
245
253
  for result in event.results
246
254
  if result.output
247
255
  }
248
256
 
249
- return results
250
-
251
- async def _retry_subscribe(self):
257
+ async def _retry_subscribe(
258
+ self,
259
+ ) -> grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]:
252
260
  retries = 0
253
261
 
254
262
  while retries < DEFAULT_WORKFLOW_LISTENER_RETRY_COUNT:
@@ -260,14 +268,19 @@ class PooledWorkflowRunListener:
260
268
  if self.curr_requester != 0:
261
269
  self.requests.put_nowait(self.curr_requester)
262
270
 
263
- listener = self.client.SubscribeToWorkflowRuns(
264
- self._request(),
265
- 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
+ ),
266
279
  )
267
-
268
- return listener
269
280
  except grpc.RpcError as e:
270
281
  if e.code() == grpc.StatusCode.UNAVAILABLE:
271
282
  retries = retries + 1
272
283
  else:
273
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))