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
@@ -0,0 +1,391 @@
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.v0 import Context
21
+ from hatchet_sdk.v0.client import Client, new_client_raw
22
+ from hatchet_sdk.v0.contracts.workflows_pb2 import CreateWorkflowVersionOpts
23
+ from hatchet_sdk.v0.loader import ClientConfig
24
+ from hatchet_sdk.v0.logger import logger
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)
@@ -0,0 +1,261 @@
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.v0 import ConcurrencyLimitStrategy
17
+ from hatchet_sdk.v0.contracts.workflows_pb2 import (
18
+ CreateWorkflowJobOpts,
19
+ CreateWorkflowStepOpts,
20
+ CreateWorkflowVersionOpts,
21
+ StickyStrategy,
22
+ WorkflowConcurrencyOpts,
23
+ WorkflowKind,
24
+ )
25
+ from hatchet_sdk.v0.logger import logger
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)
@@ -0,0 +1,59 @@
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