hatchet-sdk 0.47.1__py3-none-any.whl → 1.0.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hatchet-sdk might be problematic. Click here for more details.

Files changed (329) hide show
  1. hatchet_sdk/__init__.py +45 -25
  2. hatchet_sdk/client.py +19 -94
  3. hatchet_sdk/clients/admin.py +309 -389
  4. hatchet_sdk/clients/dispatcher/action_listener.py +131 -109
  5. hatchet_sdk/clients/dispatcher/dispatcher.py +39 -37
  6. hatchet_sdk/clients/durable_event_listener.py +327 -0
  7. hatchet_sdk/clients/event_ts.py +23 -10
  8. hatchet_sdk/clients/events.py +96 -99
  9. hatchet_sdk/clients/rest/__init__.py +35 -0
  10. hatchet_sdk/clients/rest/api/__init__.py +2 -0
  11. hatchet_sdk/clients/rest/api/log_api.py +258 -0
  12. hatchet_sdk/clients/rest/api/task_api.py +2200 -0
  13. hatchet_sdk/clients/rest/api/workflow_runs_api.py +1274 -116
  14. hatchet_sdk/clients/rest/api_client.py +1 -1
  15. hatchet_sdk/clients/rest/configuration.py +8 -1
  16. hatchet_sdk/clients/rest/exceptions.py +21 -0
  17. hatchet_sdk/clients/rest/models/__init__.py +33 -0
  18. hatchet_sdk/clients/rest/models/tenant.py +4 -0
  19. hatchet_sdk/clients/rest/models/tenant_version.py +37 -0
  20. hatchet_sdk/clients/rest/models/update_tenant_request.py +7 -0
  21. hatchet_sdk/clients/rest/models/v1_cancel_task_request.py +104 -0
  22. hatchet_sdk/clients/rest/models/v1_dag_children.py +102 -0
  23. hatchet_sdk/clients/rest/models/v1_log_line.py +94 -0
  24. hatchet_sdk/clients/rest/models/v1_log_line_level.py +39 -0
  25. hatchet_sdk/clients/rest/models/v1_log_line_list.py +110 -0
  26. hatchet_sdk/clients/rest/models/v1_replay_task_request.py +104 -0
  27. hatchet_sdk/clients/rest/models/v1_task.py +174 -0
  28. hatchet_sdk/clients/rest/models/v1_task_event.py +118 -0
  29. hatchet_sdk/clients/rest/models/v1_task_event_list.py +110 -0
  30. hatchet_sdk/clients/rest/models/v1_task_event_type.py +55 -0
  31. hatchet_sdk/clients/rest/models/v1_task_filter.py +106 -0
  32. hatchet_sdk/clients/rest/models/v1_task_point_metric.py +92 -0
  33. hatchet_sdk/clients/rest/models/v1_task_point_metrics.py +100 -0
  34. hatchet_sdk/clients/rest/models/v1_task_run_metric.py +88 -0
  35. hatchet_sdk/clients/rest/models/v1_task_run_status.py +40 -0
  36. hatchet_sdk/clients/rest/models/v1_task_status.py +40 -0
  37. hatchet_sdk/clients/rest/models/v1_task_summary.py +228 -0
  38. hatchet_sdk/clients/rest/models/v1_task_summary_list.py +110 -0
  39. hatchet_sdk/clients/rest/models/v1_trigger_workflow_run_request.py +95 -0
  40. hatchet_sdk/clients/rest/models/v1_workflow_run.py +171 -0
  41. hatchet_sdk/clients/rest/models/v1_workflow_run_details.py +145 -0
  42. hatchet_sdk/clients/rest/models/v1_workflow_run_display_name.py +98 -0
  43. hatchet_sdk/clients/rest/models/v1_workflow_run_display_name_list.py +114 -0
  44. hatchet_sdk/clients/rest/models/v1_workflow_type.py +37 -0
  45. hatchet_sdk/clients/rest/models/workflow_run_shape_item_for_workflow_run_details.py +104 -0
  46. hatchet_sdk/clients/rest/rest.py +37 -26
  47. hatchet_sdk/clients/rest/tenacity_utils.py +1 -1
  48. hatchet_sdk/clients/rest_client.py +153 -116
  49. hatchet_sdk/clients/run_event_listener.py +65 -60
  50. hatchet_sdk/clients/workflow_listener.py +75 -66
  51. hatchet_sdk/config.py +117 -0
  52. hatchet_sdk/connection.py +27 -13
  53. hatchet_sdk/context/__init__.py +0 -1
  54. hatchet_sdk/context/context.py +118 -280
  55. hatchet_sdk/contracts/dispatcher_pb2_grpc.py +1 -1
  56. hatchet_sdk/contracts/events_pb2.py +2 -2
  57. hatchet_sdk/contracts/events_pb2_grpc.py +1 -1
  58. hatchet_sdk/contracts/v1/dispatcher_pb2.py +36 -0
  59. hatchet_sdk/contracts/v1/dispatcher_pb2.pyi +38 -0
  60. hatchet_sdk/contracts/v1/dispatcher_pb2_grpc.py +145 -0
  61. hatchet_sdk/contracts/v1/shared/condition_pb2.py +39 -0
  62. hatchet_sdk/contracts/v1/shared/condition_pb2.pyi +72 -0
  63. hatchet_sdk/contracts/v1/shared/condition_pb2_grpc.py +29 -0
  64. hatchet_sdk/contracts/v1/workflows_pb2.py +67 -0
  65. hatchet_sdk/contracts/v1/workflows_pb2.pyi +228 -0
  66. hatchet_sdk/contracts/v1/workflows_pb2_grpc.py +234 -0
  67. hatchet_sdk/contracts/workflows_pb2_grpc.py +1 -1
  68. hatchet_sdk/features/cron.py +43 -57
  69. hatchet_sdk/features/scheduled.py +60 -74
  70. hatchet_sdk/hatchet.py +491 -218
  71. hatchet_sdk/labels.py +4 -6
  72. hatchet_sdk/metadata.py +1 -1
  73. hatchet_sdk/opentelemetry/instrumentor.py +17 -18
  74. hatchet_sdk/rate_limit.py +40 -55
  75. hatchet_sdk/runnables/contextvars.py +12 -0
  76. hatchet_sdk/runnables/standalone.py +194 -0
  77. hatchet_sdk/runnables/task.py +144 -0
  78. hatchet_sdk/runnables/types.py +138 -0
  79. hatchet_sdk/runnables/workflow.py +764 -0
  80. hatchet_sdk/token.py +13 -9
  81. hatchet_sdk/utils/aio_utils.py +0 -119
  82. hatchet_sdk/utils/proto_enums.py +47 -0
  83. hatchet_sdk/utils/timedelta_to_expression.py +23 -0
  84. hatchet_sdk/utils/typing.py +10 -2
  85. hatchet_sdk/v0/__init__.py +251 -0
  86. hatchet_sdk/v0/client.py +119 -0
  87. hatchet_sdk/v0/clients/admin.py +541 -0
  88. hatchet_sdk/v0/clients/dispatcher/action_listener.py +422 -0
  89. hatchet_sdk/v0/clients/dispatcher/dispatcher.py +204 -0
  90. hatchet_sdk/v0/clients/event_ts.py +28 -0
  91. hatchet_sdk/v0/clients/events.py +182 -0
  92. hatchet_sdk/v0/clients/rest/__init__.py +307 -0
  93. hatchet_sdk/v0/clients/rest/api/__init__.py +19 -0
  94. hatchet_sdk/v0/clients/rest/api/api_token_api.py +858 -0
  95. hatchet_sdk/v0/clients/rest/api/default_api.py +2259 -0
  96. hatchet_sdk/v0/clients/rest/api/event_api.py +2548 -0
  97. hatchet_sdk/v0/clients/rest/api/github_api.py +331 -0
  98. hatchet_sdk/v0/clients/rest/api/healthcheck_api.py +483 -0
  99. hatchet_sdk/v0/clients/rest/api/log_api.py +449 -0
  100. hatchet_sdk/v0/clients/rest/api/metadata_api.py +728 -0
  101. hatchet_sdk/v0/clients/rest/api/rate_limits_api.py +423 -0
  102. hatchet_sdk/v0/clients/rest/api/slack_api.py +577 -0
  103. hatchet_sdk/v0/clients/rest/api/sns_api.py +872 -0
  104. hatchet_sdk/v0/clients/rest/api/step_run_api.py +2202 -0
  105. hatchet_sdk/v0/clients/rest/api/tenant_api.py +4430 -0
  106. hatchet_sdk/v0/clients/rest/api/user_api.py +2888 -0
  107. hatchet_sdk/v0/clients/rest/api/worker_api.py +858 -0
  108. hatchet_sdk/v0/clients/rest/api/workflow_api.py +6312 -0
  109. hatchet_sdk/v0/clients/rest/api/workflow_run_api.py +1932 -0
  110. hatchet_sdk/v0/clients/rest/api/workflow_runs_api.py +610 -0
  111. hatchet_sdk/v0/clients/rest/api_client.py +759 -0
  112. hatchet_sdk/v0/clients/rest/api_response.py +22 -0
  113. hatchet_sdk/v0/clients/rest/configuration.py +611 -0
  114. hatchet_sdk/v0/clients/rest/exceptions.py +200 -0
  115. hatchet_sdk/v0/clients/rest/models/__init__.py +274 -0
  116. hatchet_sdk/v0/clients/rest/models/accept_invite_request.py +83 -0
  117. hatchet_sdk/v0/clients/rest/models/api_error.py +102 -0
  118. hatchet_sdk/v0/clients/rest/models/api_errors.py +100 -0
  119. hatchet_sdk/v0/clients/rest/models/api_meta.py +144 -0
  120. hatchet_sdk/v0/clients/rest/models/api_meta_auth.py +85 -0
  121. hatchet_sdk/v0/clients/rest/models/api_meta_integration.py +88 -0
  122. hatchet_sdk/v0/clients/rest/models/api_meta_posthog.py +90 -0
  123. hatchet_sdk/v0/clients/rest/models/api_resource_meta.py +98 -0
  124. hatchet_sdk/v0/clients/rest/models/api_token.py +105 -0
  125. hatchet_sdk/v0/clients/rest/models/bulk_create_event_request.py +100 -0
  126. hatchet_sdk/v0/clients/rest/models/bulk_create_event_response.py +110 -0
  127. hatchet_sdk/v0/clients/rest/models/cancel_event_request.py +85 -0
  128. hatchet_sdk/v0/clients/rest/models/cancel_step_run_request.py +83 -0
  129. hatchet_sdk/v0/clients/rest/models/concurrency_limit_strategy.py +39 -0
  130. hatchet_sdk/v0/clients/rest/models/create_api_token_request.py +92 -0
  131. hatchet_sdk/v0/clients/rest/models/create_api_token_response.py +83 -0
  132. hatchet_sdk/v0/clients/rest/models/create_cron_workflow_trigger_request.py +98 -0
  133. hatchet_sdk/v0/clients/rest/models/create_event_request.py +95 -0
  134. hatchet_sdk/v0/clients/rest/models/create_pull_request_from_step_run.py +83 -0
  135. hatchet_sdk/v0/clients/rest/models/create_sns_integration_request.py +85 -0
  136. hatchet_sdk/v0/clients/rest/models/create_tenant_alert_email_group_request.py +83 -0
  137. hatchet_sdk/v0/clients/rest/models/create_tenant_invite_request.py +86 -0
  138. hatchet_sdk/v0/clients/rest/models/create_tenant_request.py +84 -0
  139. hatchet_sdk/v0/clients/rest/models/cron_workflows.py +131 -0
  140. hatchet_sdk/v0/clients/rest/models/cron_workflows_list.py +110 -0
  141. hatchet_sdk/v0/clients/rest/models/cron_workflows_method.py +37 -0
  142. hatchet_sdk/v0/clients/rest/models/cron_workflows_order_by_field.py +37 -0
  143. hatchet_sdk/v0/clients/rest/models/event.py +143 -0
  144. hatchet_sdk/v0/clients/rest/models/event_data.py +83 -0
  145. hatchet_sdk/v0/clients/rest/models/event_key_list.py +98 -0
  146. hatchet_sdk/v0/clients/rest/models/event_list.py +110 -0
  147. hatchet_sdk/v0/clients/rest/models/event_order_by_direction.py +37 -0
  148. hatchet_sdk/v0/clients/rest/models/event_order_by_field.py +36 -0
  149. hatchet_sdk/v0/clients/rest/models/event_update_cancel200_response.py +85 -0
  150. hatchet_sdk/v0/clients/rest/models/event_workflow_run_summary.py +116 -0
  151. hatchet_sdk/v0/clients/rest/models/events.py +110 -0
  152. hatchet_sdk/v0/clients/rest/models/get_step_run_diff_response.py +100 -0
  153. hatchet_sdk/v0/clients/rest/models/github_app_installation.py +107 -0
  154. hatchet_sdk/v0/clients/rest/models/github_branch.py +86 -0
  155. hatchet_sdk/v0/clients/rest/models/github_repo.py +86 -0
  156. hatchet_sdk/v0/clients/rest/models/info_get_version200_response.py +83 -0
  157. hatchet_sdk/v0/clients/rest/models/job.py +132 -0
  158. hatchet_sdk/v0/clients/rest/models/job_run.py +176 -0
  159. hatchet_sdk/v0/clients/rest/models/job_run_status.py +41 -0
  160. hatchet_sdk/v0/clients/rest/models/link_github_repository_request.py +106 -0
  161. hatchet_sdk/v0/clients/rest/models/list_api_tokens_response.py +110 -0
  162. hatchet_sdk/v0/clients/rest/models/list_github_app_installations_response.py +112 -0
  163. hatchet_sdk/v0/clients/rest/models/list_pull_requests_response.py +100 -0
  164. hatchet_sdk/v0/clients/rest/models/list_slack_webhooks.py +110 -0
  165. hatchet_sdk/v0/clients/rest/models/list_sns_integrations.py +110 -0
  166. hatchet_sdk/v0/clients/rest/models/log_line.py +94 -0
  167. hatchet_sdk/v0/clients/rest/models/log_line_level.py +39 -0
  168. hatchet_sdk/v0/clients/rest/models/log_line_list.py +110 -0
  169. hatchet_sdk/v0/clients/rest/models/log_line_order_by_direction.py +37 -0
  170. hatchet_sdk/v0/clients/rest/models/log_line_order_by_field.py +36 -0
  171. hatchet_sdk/v0/clients/rest/models/pagination_response.py +95 -0
  172. hatchet_sdk/v0/clients/rest/models/pull_request.py +112 -0
  173. hatchet_sdk/v0/clients/rest/models/pull_request_state.py +37 -0
  174. hatchet_sdk/v0/clients/rest/models/queue_metrics.py +97 -0
  175. hatchet_sdk/v0/clients/rest/models/rate_limit.py +117 -0
  176. hatchet_sdk/v0/clients/rest/models/rate_limit_list.py +110 -0
  177. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_direction.py +37 -0
  178. hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_field.py +38 -0
  179. hatchet_sdk/v0/clients/rest/models/recent_step_runs.py +118 -0
  180. hatchet_sdk/v0/clients/rest/models/reject_invite_request.py +83 -0
  181. hatchet_sdk/v0/clients/rest/models/replay_event_request.py +85 -0
  182. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_request.py +85 -0
  183. hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_response.py +100 -0
  184. hatchet_sdk/v0/clients/rest/models/rerun_step_run_request.py +83 -0
  185. hatchet_sdk/v0/clients/rest/models/schedule_workflow_run_request.py +92 -0
  186. hatchet_sdk/v0/clients/rest/models/scheduled_run_status.py +42 -0
  187. hatchet_sdk/v0/clients/rest/models/scheduled_workflows.py +149 -0
  188. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_list.py +110 -0
  189. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_method.py +37 -0
  190. hatchet_sdk/v0/clients/rest/models/scheduled_workflows_order_by_field.py +37 -0
  191. hatchet_sdk/v0/clients/rest/models/semaphore_slots.py +113 -0
  192. hatchet_sdk/v0/clients/rest/models/slack_webhook.py +127 -0
  193. hatchet_sdk/v0/clients/rest/models/sns_integration.py +114 -0
  194. hatchet_sdk/v0/clients/rest/models/step.py +123 -0
  195. hatchet_sdk/v0/clients/rest/models/step_run.py +202 -0
  196. hatchet_sdk/v0/clients/rest/models/step_run_archive.py +142 -0
  197. hatchet_sdk/v0/clients/rest/models/step_run_archive_list.py +110 -0
  198. hatchet_sdk/v0/clients/rest/models/step_run_diff.py +91 -0
  199. hatchet_sdk/v0/clients/rest/models/step_run_event.py +122 -0
  200. hatchet_sdk/v0/clients/rest/models/step_run_event_list.py +110 -0
  201. hatchet_sdk/v0/clients/rest/models/step_run_event_reason.py +52 -0
  202. hatchet_sdk/v0/clients/rest/models/step_run_event_severity.py +38 -0
  203. hatchet_sdk/v0/clients/rest/models/step_run_status.py +44 -0
  204. hatchet_sdk/v0/clients/rest/models/tenant.py +118 -0
  205. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group.py +98 -0
  206. hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group_list.py +112 -0
  207. hatchet_sdk/v0/clients/rest/models/tenant_alerting_settings.py +143 -0
  208. hatchet_sdk/v0/clients/rest/models/tenant_invite.py +120 -0
  209. hatchet_sdk/v0/clients/rest/models/tenant_invite_list.py +110 -0
  210. hatchet_sdk/v0/clients/rest/models/tenant_list.py +110 -0
  211. hatchet_sdk/v0/clients/rest/models/tenant_member.py +123 -0
  212. hatchet_sdk/v0/clients/rest/models/tenant_member_list.py +110 -0
  213. hatchet_sdk/v0/clients/rest/models/tenant_member_role.py +38 -0
  214. hatchet_sdk/v0/clients/rest/models/tenant_queue_metrics.py +116 -0
  215. hatchet_sdk/v0/clients/rest/models/tenant_resource.py +40 -0
  216. hatchet_sdk/v0/clients/rest/models/tenant_resource_limit.py +135 -0
  217. hatchet_sdk/v0/clients/rest/models/tenant_resource_policy.py +102 -0
  218. hatchet_sdk/v0/clients/rest/models/tenant_step_run_queue_metrics.py +83 -0
  219. hatchet_sdk/v0/clients/rest/models/trigger_workflow_run_request.py +91 -0
  220. hatchet_sdk/v0/clients/rest/models/update_tenant_alert_email_group_request.py +83 -0
  221. hatchet_sdk/v0/clients/rest/models/update_tenant_invite_request.py +85 -0
  222. hatchet_sdk/v0/clients/rest/models/update_tenant_request.py +137 -0
  223. hatchet_sdk/v0/clients/rest/models/update_worker_request.py +87 -0
  224. hatchet_sdk/v0/clients/rest/models/user.py +126 -0
  225. hatchet_sdk/v0/clients/rest/models/user_change_password_request.py +88 -0
  226. hatchet_sdk/v0/clients/rest/models/user_login_request.py +86 -0
  227. hatchet_sdk/v0/clients/rest/models/user_register_request.py +91 -0
  228. hatchet_sdk/v0/clients/rest/models/user_tenant_memberships_list.py +110 -0
  229. hatchet_sdk/v0/clients/rest/models/user_tenant_public.py +86 -0
  230. hatchet_sdk/v0/clients/rest/models/webhook_worker.py +100 -0
  231. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_request.py +94 -0
  232. hatchet_sdk/v0/clients/rest/models/webhook_worker_create_response.py +98 -0
  233. hatchet_sdk/v0/clients/rest/models/webhook_worker_created.py +102 -0
  234. hatchet_sdk/v0/clients/rest/models/webhook_worker_list_response.py +110 -0
  235. hatchet_sdk/v0/clients/rest/models/webhook_worker_request.py +102 -0
  236. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_list_response.py +104 -0
  237. hatchet_sdk/v0/clients/rest/models/webhook_worker_request_method.py +38 -0
  238. hatchet_sdk/v0/clients/rest/models/worker.py +239 -0
  239. hatchet_sdk/v0/clients/rest/models/worker_label.py +102 -0
  240. hatchet_sdk/v0/clients/rest/models/worker_list.py +110 -0
  241. hatchet_sdk/v0/clients/rest/models/worker_runtime_info.py +103 -0
  242. hatchet_sdk/v0/clients/rest/models/worker_runtime_sdks.py +38 -0
  243. hatchet_sdk/v0/clients/rest/models/worker_type.py +38 -0
  244. hatchet_sdk/v0/clients/rest/models/workflow.py +165 -0
  245. hatchet_sdk/v0/clients/rest/models/workflow_concurrency.py +107 -0
  246. hatchet_sdk/v0/clients/rest/models/workflow_deployment_config.py +136 -0
  247. hatchet_sdk/v0/clients/rest/models/workflow_kind.py +38 -0
  248. hatchet_sdk/v0/clients/rest/models/workflow_list.py +120 -0
  249. hatchet_sdk/v0/clients/rest/models/workflow_metrics.py +97 -0
  250. hatchet_sdk/v0/clients/rest/models/workflow_run.py +188 -0
  251. hatchet_sdk/v0/clients/rest/models/workflow_run_cancel200_response.py +85 -0
  252. hatchet_sdk/v0/clients/rest/models/workflow_run_list.py +110 -0
  253. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_direction.py +37 -0
  254. hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_field.py +39 -0
  255. hatchet_sdk/v0/clients/rest/models/workflow_run_shape.py +186 -0
  256. hatchet_sdk/v0/clients/rest/models/workflow_run_status.py +42 -0
  257. hatchet_sdk/v0/clients/rest/models/workflow_run_triggered_by.py +112 -0
  258. hatchet_sdk/v0/clients/rest/models/workflow_runs_cancel_request.py +85 -0
  259. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics.py +94 -0
  260. hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics_counts.py +104 -0
  261. hatchet_sdk/v0/clients/rest/models/workflow_tag.py +84 -0
  262. hatchet_sdk/v0/clients/rest/models/workflow_trigger_cron_ref.py +86 -0
  263. hatchet_sdk/v0/clients/rest/models/workflow_trigger_event_ref.py +86 -0
  264. hatchet_sdk/v0/clients/rest/models/workflow_triggers.py +141 -0
  265. hatchet_sdk/v0/clients/rest/models/workflow_update_request.py +85 -0
  266. hatchet_sdk/v0/clients/rest/models/workflow_version.py +170 -0
  267. hatchet_sdk/v0/clients/rest/models/workflow_version_concurrency.py +114 -0
  268. hatchet_sdk/v0/clients/rest/models/workflow_version_definition.py +85 -0
  269. hatchet_sdk/v0/clients/rest/models/workflow_version_meta.py +123 -0
  270. hatchet_sdk/v0/clients/rest/models/workflow_workers_count.py +95 -0
  271. hatchet_sdk/v0/clients/rest/rest.py +187 -0
  272. hatchet_sdk/v0/clients/rest/tenacity_utils.py +39 -0
  273. hatchet_sdk/v0/clients/rest_client.py +622 -0
  274. hatchet_sdk/v0/clients/run_event_listener.py +260 -0
  275. hatchet_sdk/v0/clients/workflow_listener.py +277 -0
  276. hatchet_sdk/v0/connection.py +63 -0
  277. hatchet_sdk/v0/context/__init__.py +1 -0
  278. hatchet_sdk/v0/context/context.py +446 -0
  279. hatchet_sdk/v0/context/worker_context.py +28 -0
  280. hatchet_sdk/v0/contracts/dispatcher_pb2.py +102 -0
  281. hatchet_sdk/v0/contracts/dispatcher_pb2.pyi +387 -0
  282. hatchet_sdk/v0/contracts/dispatcher_pb2_grpc.py +621 -0
  283. hatchet_sdk/v0/contracts/events_pb2.py +46 -0
  284. hatchet_sdk/v0/contracts/events_pb2.pyi +87 -0
  285. hatchet_sdk/v0/contracts/events_pb2_grpc.py +274 -0
  286. hatchet_sdk/v0/contracts/workflows_pb2.py +80 -0
  287. hatchet_sdk/v0/contracts/workflows_pb2.pyi +312 -0
  288. hatchet_sdk/v0/contracts/workflows_pb2_grpc.py +277 -0
  289. hatchet_sdk/v0/features/cron.py +286 -0
  290. hatchet_sdk/v0/features/scheduled.py +248 -0
  291. hatchet_sdk/v0/hatchet.py +310 -0
  292. hatchet_sdk/v0/labels.py +10 -0
  293. hatchet_sdk/v0/logger.py +13 -0
  294. hatchet_sdk/v0/metadata.py +2 -0
  295. hatchet_sdk/v0/opentelemetry/instrumentor.py +396 -0
  296. hatchet_sdk/v0/rate_limit.py +126 -0
  297. hatchet_sdk/v0/token.py +27 -0
  298. hatchet_sdk/v0/utils/aio_utils.py +137 -0
  299. hatchet_sdk/v0/utils/backoff.py +9 -0
  300. hatchet_sdk/v0/utils/typing.py +12 -0
  301. hatchet_sdk/{v2 → v0/v2}/callable.py +8 -8
  302. hatchet_sdk/{v2 → v0/v2}/concurrency.py +2 -2
  303. hatchet_sdk/{v2 → v0/v2}/hatchet.py +10 -10
  304. hatchet_sdk/v0/worker/__init__.py +1 -0
  305. hatchet_sdk/v0/worker/action_listener_process.py +294 -0
  306. hatchet_sdk/v0/worker/runner/run_loop_manager.py +112 -0
  307. hatchet_sdk/v0/worker/runner/runner.py +460 -0
  308. hatchet_sdk/v0/worker/runner/utils/capture_logs.py +81 -0
  309. hatchet_sdk/v0/worker/worker.py +391 -0
  310. hatchet_sdk/{workflow.py → v0/workflow.py} +4 -4
  311. hatchet_sdk/v0/workflow_run.py +59 -0
  312. hatchet_sdk/waits.py +120 -0
  313. hatchet_sdk/worker/__init__.py +0 -1
  314. hatchet_sdk/worker/action_listener_process.py +80 -55
  315. hatchet_sdk/worker/runner/run_loop_manager.py +46 -34
  316. hatchet_sdk/worker/runner/runner.py +82 -87
  317. hatchet_sdk/worker/runner/utils/capture_logs.py +26 -23
  318. hatchet_sdk/worker/worker.py +172 -149
  319. hatchet_sdk/workflow_run.py +7 -21
  320. {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.dist-info}/METADATA +2 -2
  321. hatchet_sdk-1.0.0a1.dist-info/RECORD +505 -0
  322. {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.dist-info}/entry_points.txt +2 -0
  323. hatchet_sdk/utils/serialization.py +0 -18
  324. hatchet_sdk-0.47.1.dist-info/RECORD +0 -237
  325. /hatchet_sdk/{loader.py → v0/loader.py} +0 -0
  326. /hatchet_sdk/{semver.py → v0/semver.py} +0 -0
  327. /hatchet_sdk/{utils → v0/utils}/types.py +0 -0
  328. /hatchet_sdk/{worker → v0/worker}/runner/utils/error_with_traceback.py +0 -0
  329. {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.dist-info}/WHEEL +0 -0
@@ -1,70 +1,56 @@
1
+ import asyncio
1
2
  import json
2
3
  from datetime import datetime
3
- from typing import Any, Callable, Dict, List, Optional, TypedDict, TypeVar, Union
4
+ from typing import Union, cast
4
5
 
5
6
  import grpc
6
7
  from google.protobuf import timestamp_pb2
8
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
7
9
 
8
- from hatchet_sdk.clients.rest.models.workflow_run import WorkflowRun
9
10
  from hatchet_sdk.clients.rest.tenacity_utils import tenacity_retry
10
- from hatchet_sdk.clients.run_event_listener import new_listener
11
+ from hatchet_sdk.clients.run_event_listener import RunEventListenerClient
11
12
  from hatchet_sdk.clients.workflow_listener import PooledWorkflowRunListener
13
+ from hatchet_sdk.config import ClientConfig
12
14
  from hatchet_sdk.connection import new_conn
13
- from hatchet_sdk.contracts.workflows_pb2 import (
14
- BulkTriggerWorkflowRequest,
15
- BulkTriggerWorkflowResponse,
16
- CreateWorkflowVersionOpts,
17
- PutRateLimitRequest,
18
- PutWorkflowRequest,
19
- RateLimitDuration,
20
- ScheduleWorkflowRequest,
21
- TriggerWorkflowRequest,
22
- TriggerWorkflowResponse,
23
- WorkflowVersion,
24
- )
15
+ from hatchet_sdk.contracts import workflows_pb2 as v0_workflow_protos
16
+ from hatchet_sdk.contracts.v1 import workflows_pb2 as workflow_protos
17
+ from hatchet_sdk.contracts.v1.workflows_pb2_grpc import AdminServiceStub
25
18
  from hatchet_sdk.contracts.workflows_pb2_grpc import WorkflowServiceStub
26
- from hatchet_sdk.utils.serialization import flatten
27
- from hatchet_sdk.workflow_run import RunRef, WorkflowRunRef
28
-
29
- from ..loader import ClientConfig
30
- from ..metadata import get_metadata
31
- from ..workflow import WorkflowMeta
32
-
33
-
34
- def new_admin(config: ClientConfig):
35
- return AdminClient(config)
36
-
37
-
38
- class ScheduleTriggerWorkflowOptions(TypedDict, total=False):
39
- parent_id: Optional[str]
40
- parent_step_run_id: Optional[str]
41
- child_index: Optional[int]
42
- child_key: Optional[str]
43
- namespace: Optional[str]
44
-
45
-
46
- class ChildTriggerWorkflowOptions(TypedDict, total=False):
47
- additional_metadata: Dict[str, str] | None = None
48
- sticky: bool | None = None
19
+ from hatchet_sdk.metadata import get_metadata
20
+ from hatchet_sdk.rate_limit import RateLimitDuration
21
+ from hatchet_sdk.runnables.contextvars import (
22
+ ctx_step_run_id,
23
+ ctx_worker_id,
24
+ ctx_workflow_run_id,
25
+ spawn_index_lock,
26
+ workflow_spawn_indices,
27
+ )
28
+ from hatchet_sdk.utils.proto_enums import convert_python_enum_to_proto
29
+ from hatchet_sdk.utils.typing import JSONSerializableMapping
30
+ from hatchet_sdk.workflow_run import WorkflowRunRef
49
31
 
50
32
 
51
- class ChildWorkflowRunDict(TypedDict, total=False):
52
- workflow_name: str
53
- input: Any
54
- options: ChildTriggerWorkflowOptions
55
- key: str | None = None
33
+ class ScheduleTriggerWorkflowOptions(BaseModel):
34
+ parent_id: str | None = None
35
+ parent_step_run_id: str | None = None
36
+ child_index: int | None = None
37
+ child_key: str | None = None
38
+ namespace: str | None = None
56
39
 
57
40
 
58
- class TriggerWorkflowOptions(ScheduleTriggerWorkflowOptions, total=False):
59
- additional_metadata: Dict[str, str] | None = None
41
+ class TriggerWorkflowOptions(ScheduleTriggerWorkflowOptions):
42
+ additional_metadata: JSONSerializableMapping = Field(default_factory=dict)
60
43
  desired_worker_id: str | None = None
61
44
  namespace: str | None = None
45
+ sticky: bool = False
46
+ key: str | None = None
62
47
 
63
48
 
64
- class WorkflowRunDict(TypedDict, total=False):
49
+ class WorkflowRunTriggerConfig(BaseModel):
65
50
  workflow_name: str
66
- input: Any
67
- options: TriggerWorkflowOptions | None
51
+ input: JSONSerializableMapping
52
+ options: TriggerWorkflowOptions
53
+ key: str | None = None
68
54
 
69
55
 
70
56
  class DedupeViolationErr(Exception):
@@ -73,259 +59,198 @@ class DedupeViolationErr(Exception):
73
59
  pass
74
60
 
75
61
 
76
- class AdminClientBase:
77
- pooled_workflow_listener: PooledWorkflowRunListener | None = None
62
+ class AdminClient:
63
+ def __init__(self, config: ClientConfig):
64
+ conn = new_conn(config, False)
65
+ self.config = config
66
+ self.client = AdminServiceStub(conn) # type: ignore[no-untyped-call]
67
+ self.v0_client = WorkflowServiceStub(conn) # type: ignore[no-untyped-call]
68
+ self.token = config.token
69
+ self.listener_client = RunEventListenerClient(config=config)
70
+ self.namespace = config.namespace
78
71
 
79
- def _prepare_workflow_request(
80
- self, workflow_name: str, input: any, options: TriggerWorkflowOptions = None
81
- ):
82
- try:
83
- payload_data = json.dumps(input)
72
+ self.pooled_workflow_listener: PooledWorkflowRunListener | None = None
73
+
74
+ class TriggerWorkflowRequest(BaseModel):
75
+ model_config = ConfigDict(extra="ignore")
76
+
77
+ parent_id: str | None = None
78
+ parent_step_run_id: str | None = None
79
+ child_index: int | None = None
80
+ child_key: str | None = None
81
+ additional_metadata: str | None = None
82
+ desired_worker_id: str | None = None
83
+ priority: int | None = None
84
+
85
+ @field_validator("additional_metadata", mode="before")
86
+ @classmethod
87
+ def validate_additional_metadata(
88
+ cls, v: JSONSerializableMapping | None
89
+ ) -> bytes | None:
90
+ if not v:
91
+ return None
84
92
 
85
93
  try:
86
- meta = (
87
- None
88
- if options is None or "additional_metadata" not in options
89
- else options["additional_metadata"]
90
- )
91
- if meta is not None:
92
- options = {
93
- **options,
94
- "additional_metadata": json.dumps(meta).encode("utf-8"),
95
- }
94
+ return json.dumps(v).encode("utf-8")
96
95
  except json.JSONDecodeError as e:
97
96
  raise ValueError(f"Error encoding payload: {e}")
98
97
 
99
- return TriggerWorkflowRequest(
100
- name=workflow_name, input=payload_data, **(options or {})
101
- )
98
+ def _prepare_workflow_request(
99
+ self,
100
+ workflow_name: str,
101
+ input: JSONSerializableMapping,
102
+ options: TriggerWorkflowOptions,
103
+ ) -> v0_workflow_protos.TriggerWorkflowRequest:
104
+ try:
105
+ payload_data = json.dumps(input)
102
106
  except json.JSONDecodeError as e:
103
107
  raise ValueError(f"Error encoding payload: {e}")
104
108
 
109
+ _options = self.TriggerWorkflowRequest.model_validate(
110
+ options.model_dump()
111
+ ).model_dump()
112
+
113
+ return v0_workflow_protos.TriggerWorkflowRequest(
114
+ name=workflow_name, input=payload_data, **_options
115
+ )
116
+
105
117
  def _prepare_put_workflow_request(
106
118
  self,
107
119
  name: str,
108
- workflow: CreateWorkflowVersionOpts | WorkflowMeta,
109
- overrides: CreateWorkflowVersionOpts | None = None,
110
- ):
111
- try:
112
- opts: CreateWorkflowVersionOpts
113
-
114
- if isinstance(workflow, CreateWorkflowVersionOpts):
115
- opts = workflow
116
- else:
117
- opts = workflow.get_create_opts(self.client.config.namespace)
118
-
119
- if overrides is not None:
120
- opts.MergeFrom(overrides)
121
-
122
- opts.name = name
123
-
124
- return PutWorkflowRequest(
125
- opts=opts,
120
+ workflow: workflow_protos.CreateWorkflowVersionRequest,
121
+ overrides: workflow_protos.CreateWorkflowVersionRequest | None = None,
122
+ ) -> workflow_protos.CreateWorkflowVersionRequest:
123
+ if overrides is not None:
124
+ workflow.MergeFrom(overrides)
125
+
126
+ workflow.name = name
127
+
128
+ return workflow
129
+
130
+ def _parse_schedule(
131
+ self, schedule: datetime | timestamp_pb2.Timestamp
132
+ ) -> timestamp_pb2.Timestamp:
133
+ if isinstance(schedule, datetime):
134
+ t = schedule.timestamp()
135
+ seconds = int(t)
136
+ nanos = int(t % 1 * 1e9)
137
+ return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)
138
+ elif isinstance(schedule, timestamp_pb2.Timestamp):
139
+ return schedule
140
+ else:
141
+ raise ValueError(
142
+ "Invalid schedule type. Must be datetime or timestamp_pb2.Timestamp."
126
143
  )
127
- except grpc.RpcError as e:
128
- raise ValueError(f"Could not put workflow: {e}")
129
144
 
130
145
  def _prepare_schedule_workflow_request(
131
146
  self,
132
147
  name: str,
133
- schedules: List[Union[datetime, timestamp_pb2.Timestamp]],
134
- input={},
135
- options: ScheduleTriggerWorkflowOptions = None,
136
- ):
137
- timestamp_schedules = []
138
- for schedule in schedules:
139
- if isinstance(schedule, datetime):
140
- t = schedule.timestamp()
141
- seconds = int(t)
142
- nanos = int(t % 1 * 1e9)
143
- timestamp = timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)
144
- timestamp_schedules.append(timestamp)
145
- elif isinstance(schedule, timestamp_pb2.Timestamp):
146
- timestamp_schedules.append(schedule)
147
- else:
148
- raise ValueError(
149
- "Invalid schedule type. Must be datetime or timestamp_pb2.Timestamp."
150
- )
151
-
152
- return ScheduleWorkflowRequest(
148
+ schedules: list[Union[datetime, timestamp_pb2.Timestamp]],
149
+ input: JSONSerializableMapping = {},
150
+ options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
151
+ ) -> v0_workflow_protos.ScheduleWorkflowRequest:
152
+ return v0_workflow_protos.ScheduleWorkflowRequest(
153
153
  name=name,
154
- schedules=timestamp_schedules,
154
+ schedules=[self._parse_schedule(schedule) for schedule in schedules],
155
155
  input=json.dumps(input),
156
- **(options or {}),
156
+ **options.model_dump(),
157
157
  )
158
158
 
159
-
160
- T = TypeVar("T")
161
-
162
-
163
- class AdminClientAioImpl(AdminClientBase):
164
- def __init__(self, config: ClientConfig):
165
- aio_conn = new_conn(config, True)
166
- self.config = config
167
- self.aio_client = WorkflowServiceStub(aio_conn)
168
- self.token = config.token
169
- self.listener_client = new_listener(config)
170
- self.namespace = config.namespace
171
-
172
- async def run(
159
+ @tenacity_retry
160
+ async def aio_put_workflow(
173
161
  self,
174
- function: Union[str, Callable[[Any], T]],
175
- input: any,
176
- options: TriggerWorkflowOptions = None,
177
- ) -> "RunRef[T]":
178
- workflow_name = function
179
-
180
- if not isinstance(function, str):
181
- workflow_name = function.function_name
182
-
183
- wrr = await self.run_workflow(workflow_name, input, options)
162
+ name: str,
163
+ workflow: workflow_protos.CreateWorkflowVersionRequest,
164
+ overrides: workflow_protos.CreateWorkflowVersionRequest | None = None,
165
+ ) -> workflow_protos.CreateWorkflowVersionResponse:
166
+ ## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
167
+ ## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
168
+ ## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
169
+ if not self.pooled_workflow_listener:
170
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
184
171
 
185
- return RunRef[T](
186
- wrr.workflow_run_id, wrr.workflow_listener, wrr.workflow_run_event_listener
187
- )
172
+ return await asyncio.to_thread(self.put_workflow, name, workflow, overrides)
188
173
 
189
- ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
190
174
  @tenacity_retry
191
- async def run_workflow(
192
- self, workflow_name: str, input: any, options: TriggerWorkflowOptions = None
193
- ) -> WorkflowRunRef:
194
- try:
195
- if not self.pooled_workflow_listener:
196
- self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
197
-
198
- namespace = self.namespace
199
-
200
- if (
201
- options is not None
202
- and "namespace" in options
203
- and options["namespace"] is not None
204
- ):
205
- namespace = options.pop("namespace")
206
-
207
- if namespace != "" and not workflow_name.startswith(self.namespace):
208
- workflow_name = f"{namespace}{workflow_name}"
209
-
210
- request = self._prepare_workflow_request(workflow_name, input, options)
211
-
212
- resp: TriggerWorkflowResponse = await self.aio_client.TriggerWorkflow(
213
- request,
214
- metadata=get_metadata(self.token),
215
- )
216
-
217
- return WorkflowRunRef(
218
- workflow_run_id=resp.workflow_run_id,
219
- workflow_listener=self.pooled_workflow_listener,
220
- workflow_run_event_listener=self.listener_client,
221
- )
222
- except (grpc.RpcError, grpc.aio.AioRpcError) as e:
223
- if e.code() == grpc.StatusCode.ALREADY_EXISTS:
224
- raise DedupeViolationErr(e.details())
175
+ async def aio_put_rate_limit(
176
+ self,
177
+ key: str,
178
+ limit: int,
179
+ duration: RateLimitDuration = RateLimitDuration.SECOND,
180
+ ) -> None:
181
+ ## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
182
+ ## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
183
+ ## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
184
+ if not self.pooled_workflow_listener:
185
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
225
186
 
226
- raise e
187
+ return await asyncio.to_thread(self.put_rate_limit, key, limit, duration)
227
188
 
228
- ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
229
189
  @tenacity_retry
230
- async def run_workflows(
190
+ async def aio_schedule_workflow(
231
191
  self,
232
- workflows: list[WorkflowRunDict],
233
- options: TriggerWorkflowOptions | None = None,
234
- ) -> List[WorkflowRunRef]:
235
- if len(workflows) == 0:
236
- raise ValueError("No workflows to run")
237
-
192
+ name: str,
193
+ schedules: list[Union[datetime, timestamp_pb2.Timestamp]],
194
+ input: JSONSerializableMapping = {},
195
+ options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
196
+ ) -> v0_workflow_protos.WorkflowVersion:
197
+ ## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
198
+ ## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
199
+ ## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
238
200
  if not self.pooled_workflow_listener:
239
201
  self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
240
202
 
241
- namespace = self.namespace
242
-
243
- if (
244
- options is not None
245
- and "namespace" in options
246
- and options["namespace"] is not None
247
- ):
248
- namespace = options["namespace"]
249
- del options["namespace"]
250
-
251
- workflow_run_requests: TriggerWorkflowRequest = []
252
-
253
- for workflow in workflows:
254
- workflow_name = workflow["workflow_name"]
255
- input_data = workflow["input"]
256
- options = workflow["options"]
257
-
258
- if namespace != "" and not workflow_name.startswith(self.namespace):
259
- workflow_name = f"{namespace}{workflow_name}"
260
-
261
- # Prepare and trigger workflow for each workflow name and input
262
- request = self._prepare_workflow_request(workflow_name, input_data, options)
263
- workflow_run_requests.append(request)
264
-
265
- request = BulkTriggerWorkflowRequest(workflows=workflow_run_requests)
266
-
267
- resp: BulkTriggerWorkflowResponse = await self.aio_client.BulkTriggerWorkflow(
268
- request,
269
- metadata=get_metadata(self.token),
203
+ return await asyncio.to_thread(
204
+ self.schedule_workflow, name, schedules, input, options
270
205
  )
271
206
 
272
- return [
273
- WorkflowRunRef(
274
- workflow_run_id=workflow_run_id,
275
- workflow_listener=self.pooled_workflow_listener,
276
- workflow_run_event_listener=self.listener_client,
277
- )
278
- for workflow_run_id in resp.workflow_run_ids
279
- ]
280
-
281
207
  @tenacity_retry
282
- async def put_workflow(
208
+ def put_workflow(
283
209
  self,
284
210
  name: str,
285
- workflow: CreateWorkflowVersionOpts | WorkflowMeta,
286
- overrides: CreateWorkflowVersionOpts | None = None,
287
- ) -> WorkflowVersion:
211
+ workflow: workflow_protos.CreateWorkflowVersionRequest,
212
+ overrides: workflow_protos.CreateWorkflowVersionRequest | None = None,
213
+ ) -> workflow_protos.CreateWorkflowVersionResponse:
288
214
  opts = self._prepare_put_workflow_request(name, workflow, overrides)
289
215
 
290
- return await self.aio_client.PutWorkflow(
291
- opts,
292
- metadata=get_metadata(self.token),
216
+ return cast(
217
+ workflow_protos.CreateWorkflowVersionResponse,
218
+ self.client.PutWorkflow(
219
+ opts,
220
+ metadata=get_metadata(self.token),
221
+ ),
293
222
  )
294
223
 
295
224
  @tenacity_retry
296
- async def put_rate_limit(
225
+ def put_rate_limit(
297
226
  self,
298
227
  key: str,
299
228
  limit: int,
300
229
  duration: RateLimitDuration = RateLimitDuration.SECOND,
301
- ):
302
- await self.aio_client.PutRateLimit(
303
- PutRateLimitRequest(
230
+ ) -> None:
231
+ duration_proto = convert_python_enum_to_proto(
232
+ duration, workflow_protos.RateLimitDuration
233
+ )
234
+
235
+ self.v0_client.PutRateLimit(
236
+ v0_workflow_protos.PutRateLimitRequest(
304
237
  key=key,
305
238
  limit=limit,
306
- duration=duration,
239
+ duration=duration_proto, # type: ignore[arg-type]
307
240
  ),
308
241
  metadata=get_metadata(self.token),
309
242
  )
310
243
 
311
244
  @tenacity_retry
312
- async def schedule_workflow(
245
+ def schedule_workflow(
313
246
  self,
314
247
  name: str,
315
- schedules: List[Union[datetime, timestamp_pb2.Timestamp]],
316
- input={},
317
- options: ScheduleTriggerWorkflowOptions = None,
318
- ) -> WorkflowVersion:
248
+ schedules: list[Union[datetime, timestamp_pb2.Timestamp]],
249
+ input: JSONSerializableMapping = {},
250
+ options: ScheduleTriggerWorkflowOptions = ScheduleTriggerWorkflowOptions(),
251
+ ) -> v0_workflow_protos.WorkflowVersion:
319
252
  try:
320
- namespace = self.namespace
321
-
322
- if (
323
- options is not None
324
- and "namespace" in options
325
- and options["namespace"] is not None
326
- ):
327
- namespace = options["namespace"]
328
- del options["namespace"]
253
+ namespace = options.namespace or self.namespace
329
254
 
330
255
  if namespace != "" and not name.startswith(self.namespace):
331
256
  name = f"{namespace}{name}"
@@ -334,128 +259,112 @@ class AdminClientAioImpl(AdminClientBase):
334
259
  name, schedules, input, options
335
260
  )
336
261
 
337
- return await self.aio_client.ScheduleWorkflow(
338
- request,
339
- metadata=get_metadata(self.token),
262
+ return cast(
263
+ v0_workflow_protos.WorkflowVersion,
264
+ self.v0_client.ScheduleWorkflow(
265
+ request,
266
+ metadata=get_metadata(self.token),
267
+ ),
340
268
  )
341
- except (grpc.aio.AioRpcError, grpc.RpcError) as e:
269
+ except (grpc.RpcError, grpc.aio.AioRpcError) as e:
342
270
  if e.code() == grpc.StatusCode.ALREADY_EXISTS:
343
271
  raise DedupeViolationErr(e.details())
344
272
 
345
273
  raise e
346
274
 
347
-
348
- class AdminClient(AdminClientBase):
349
- def __init__(self, config: ClientConfig):
350
- conn = new_conn(config)
351
- self.config = config
352
- self.client = WorkflowServiceStub(conn)
353
- self.aio = AdminClientAioImpl(config)
354
- self.token = config.token
355
- self.listener_client = new_listener(config)
356
- self.namespace = config.namespace
357
-
358
- @tenacity_retry
359
- def put_workflow(
275
+ def _create_workflow_run_request(
360
276
  self,
361
- name: str,
362
- workflow: CreateWorkflowVersionOpts | WorkflowMeta,
363
- overrides: CreateWorkflowVersionOpts | None = None,
364
- ) -> WorkflowVersion:
365
- opts = self._prepare_put_workflow_request(name, workflow, overrides)
277
+ workflow_name: str,
278
+ input: JSONSerializableMapping,
279
+ options: TriggerWorkflowOptions,
280
+ ) -> v0_workflow_protos.TriggerWorkflowRequest:
281
+ workflow_run_id = ctx_workflow_run_id.get()
282
+ step_run_id = ctx_step_run_id.get()
283
+ worker_id = ctx_worker_id.get()
284
+ spawn_index = workflow_spawn_indices[workflow_run_id] if workflow_run_id else 0
285
+
286
+ ## Increment the spawn_index for the parent workflow
287
+ if workflow_run_id:
288
+ workflow_spawn_indices[workflow_run_id] += 1
289
+
290
+ desired_worker_id = (
291
+ (options.desired_worker_id or worker_id) if options.sticky else None
292
+ )
293
+ child_index = (
294
+ options.child_index if options.child_index is not None else spawn_index
295
+ )
366
296
 
367
- resp: WorkflowVersion = self.client.PutWorkflow(
368
- opts,
369
- metadata=get_metadata(self.token),
297
+ trigger_options = TriggerWorkflowOptions(
298
+ parent_id=options.parent_id or workflow_run_id,
299
+ parent_step_run_id=options.parent_step_run_id or step_run_id,
300
+ child_key=options.child_key,
301
+ child_index=child_index,
302
+ additional_metadata=options.additional_metadata,
303
+ desired_worker_id=desired_worker_id,
370
304
  )
371
305
 
372
- return resp
306
+ namespace = options.namespace or self.namespace
373
307
 
374
- @tenacity_retry
375
- def put_rate_limit(
376
- self,
377
- key: str,
378
- limit: int,
379
- duration: Union[RateLimitDuration.Value, str] = RateLimitDuration.SECOND,
380
- ):
381
- self.client.PutRateLimit(
382
- PutRateLimitRequest(
383
- key=key,
384
- limit=limit,
385
- duration=duration,
386
- ),
387
- metadata=get_metadata(self.token),
388
- )
308
+ if namespace != "" and not workflow_name.startswith(self.namespace):
309
+ workflow_name = f"{namespace}{workflow_name}"
310
+
311
+ return self._prepare_workflow_request(workflow_name, input, trigger_options)
389
312
 
313
+ ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
390
314
  @tenacity_retry
391
- def schedule_workflow(
315
+ def run_workflow(
392
316
  self,
393
- name: str,
394
- schedules: List[Union[datetime, timestamp_pb2.Timestamp]],
395
- input={},
396
- options: ScheduleTriggerWorkflowOptions = None,
397
- ) -> WorkflowVersion:
398
- try:
399
- namespace = self.namespace
400
-
401
- if (
402
- options is not None
403
- and "namespace" in options
404
- and options["namespace"] is not None
405
- ):
406
- namespace = options["namespace"]
407
- del options["namespace"]
408
-
409
- if namespace != "" and not name.startswith(self.namespace):
410
- name = f"{namespace}{name}"
317
+ workflow_name: str,
318
+ input: JSONSerializableMapping,
319
+ options: TriggerWorkflowOptions = TriggerWorkflowOptions(),
320
+ ) -> WorkflowRunRef:
321
+ request = self._create_workflow_run_request(workflow_name, input, options)
411
322
 
412
- request = self._prepare_schedule_workflow_request(
413
- name, schedules, input, options
414
- )
323
+ if not self.pooled_workflow_listener:
324
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
415
325
 
416
- return self.client.ScheduleWorkflow(
417
- request,
418
- metadata=get_metadata(self.token),
326
+ try:
327
+ resp = cast(
328
+ v0_workflow_protos.TriggerWorkflowResponse,
329
+ self.v0_client.TriggerWorkflow(
330
+ request,
331
+ metadata=get_metadata(self.token),
332
+ ),
419
333
  )
420
334
  except (grpc.RpcError, grpc.aio.AioRpcError) as e:
421
335
  if e.code() == grpc.StatusCode.ALREADY_EXISTS:
422
336
  raise DedupeViolationErr(e.details())
423
337
 
424
- raise e
338
+ return WorkflowRunRef(
339
+ workflow_run_id=resp.workflow_run_id,
340
+ workflow_listener=self.pooled_workflow_listener,
341
+ workflow_run_event_listener=self.listener_client,
342
+ )
425
343
 
426
344
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
427
345
  @tenacity_retry
428
- def run_workflow(
429
- self, workflow_name: str, input: any, options: TriggerWorkflowOptions = None
346
+ async def aio_run_workflow(
347
+ self,
348
+ workflow_name: str,
349
+ input: JSONSerializableMapping,
350
+ options: TriggerWorkflowOptions = TriggerWorkflowOptions(),
430
351
  ) -> WorkflowRunRef:
431
- try:
432
- if not self.pooled_workflow_listener:
433
- self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
434
-
435
- namespace = self.namespace
436
-
437
- ## TODO: Factor this out - it's repeated a lot of places
438
- if (
439
- options is not None
440
- and "namespace" in options
441
- and options["namespace"] is not None
442
- ):
443
- namespace = options.pop("namespace")
444
-
445
- if namespace != "" and not workflow_name.startswith(self.namespace):
446
- workflow_name = f"{namespace}{workflow_name}"
352
+ ## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
353
+ ## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
354
+ ## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
355
+ async with spawn_index_lock:
356
+ request = self._create_workflow_run_request(workflow_name, input, options)
447
357
 
448
- request = self._prepare_workflow_request(workflow_name, input, options)
449
-
450
- resp: TriggerWorkflowResponse = self.client.TriggerWorkflow(
451
- request,
452
- metadata=get_metadata(self.token),
453
- )
358
+ if not self.pooled_workflow_listener:
359
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
454
360
 
455
- return WorkflowRunRef(
456
- workflow_run_id=resp.workflow_run_id,
457
- workflow_listener=self.pooled_workflow_listener,
458
- workflow_run_event_listener=self.listener_client,
361
+ try:
362
+ resp = cast(
363
+ v0_workflow_protos.TriggerWorkflowResponse,
364
+ self.v0_client.TriggerWorkflow(
365
+ request,
366
+ metadata=get_metadata(self.token),
367
+ ),
459
368
  )
460
369
  except (grpc.RpcError, grpc.aio.AioRpcError) as e:
461
370
  if e.code() == grpc.StatusCode.ALREADY_EXISTS:
@@ -463,43 +372,36 @@ class AdminClient(AdminClientBase):
463
372
 
464
373
  raise e
465
374
 
375
+ return WorkflowRunRef(
376
+ workflow_run_id=resp.workflow_run_id,
377
+ workflow_listener=self.pooled_workflow_listener,
378
+ workflow_run_event_listener=self.listener_client,
379
+ )
380
+
466
381
  ## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
467
382
  @tenacity_retry
468
383
  def run_workflows(
469
- self, workflows: List[WorkflowRunDict], options: TriggerWorkflowOptions = None
384
+ self,
385
+ workflows: list[WorkflowRunTriggerConfig],
470
386
  ) -> list[WorkflowRunRef]:
471
- workflow_run_requests: TriggerWorkflowRequest = []
472
387
  if not self.pooled_workflow_listener:
473
388
  self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
474
389
 
475
- for workflow in workflows:
476
- workflow_name = workflow["workflow_name"]
477
- input_data = workflow["input"]
478
- options = workflow["options"]
479
-
480
- namespace = self.namespace
481
-
482
- if (
483
- options is not None
484
- and "namespace" in options
485
- and options["namespace"] is not None
486
- ):
487
- namespace = options["namespace"]
488
- del options["namespace"]
489
-
490
- if namespace != "" and not workflow_name.startswith(self.namespace):
491
- workflow_name = f"{namespace}{workflow_name}"
492
-
493
- # Prepare and trigger workflow for each workflow name and input
494
- request = self._prepare_workflow_request(workflow_name, input_data, options)
495
-
496
- workflow_run_requests.append(request)
497
-
498
- request = BulkTriggerWorkflowRequest(workflows=workflow_run_requests)
390
+ bulk_request = v0_workflow_protos.BulkTriggerWorkflowRequest(
391
+ workflows=[
392
+ self._create_workflow_run_request(
393
+ workflow.workflow_name, workflow.input, workflow.options
394
+ )
395
+ for workflow in workflows
396
+ ]
397
+ )
499
398
 
500
- resp: BulkTriggerWorkflowResponse = self.client.BulkTriggerWorkflow(
501
- request,
502
- metadata=get_metadata(self.token),
399
+ resp = cast(
400
+ v0_workflow_protos.BulkTriggerWorkflowResponse,
401
+ self.v0_client.BulkTriggerWorkflow(
402
+ bulk_request,
403
+ metadata=get_metadata(self.token),
404
+ ),
503
405
  )
504
406
 
505
407
  return [
@@ -511,32 +413,50 @@ class AdminClient(AdminClientBase):
511
413
  for workflow_run_id in resp.workflow_run_ids
512
414
  ]
513
415
 
514
- def run(
416
+ @tenacity_retry
417
+ async def aio_run_workflows(
515
418
  self,
516
- function: Union[str, Callable[[Any], T]],
517
- input: any,
518
- options: TriggerWorkflowOptions = None,
519
- ) -> "RunRef[T]":
520
- workflow_name = function
521
-
522
- if not isinstance(function, str):
523
- workflow_name = function.function_name
419
+ workflows: list[WorkflowRunTriggerConfig],
420
+ ) -> list[WorkflowRunRef]:
421
+ ## IMPORTANT: The `pooled_workflow_listener` must be created 1) lazily, and not at `init` time, and 2) on the
422
+ ## main thread. If 1) is not followed, you'll get an error about something being attached to the wrong event
423
+ ## loop. If 2) is not followed, you'll get an error about the event loop not being set up.
424
+ if not self.pooled_workflow_listener:
425
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
524
426
 
525
- wrr = self.run_workflow(workflow_name, input, options)
427
+ async with spawn_index_lock:
428
+ bulk_request = v0_workflow_protos.BulkTriggerWorkflowRequest(
429
+ workflows=[
430
+ self._create_workflow_run_request(
431
+ workflow.workflow_name, workflow.input, workflow.options
432
+ )
433
+ for workflow in workflows
434
+ ]
435
+ )
526
436
 
527
- return RunRef[T](
528
- wrr.workflow_run_id, wrr.workflow_listener, wrr.workflow_run_event_listener
437
+ resp = cast(
438
+ v0_workflow_protos.BulkTriggerWorkflowResponse,
439
+ self.v0_client.BulkTriggerWorkflow(
440
+ bulk_request,
441
+ metadata=get_metadata(self.token),
442
+ ),
529
443
  )
530
444
 
531
- def get_workflow_run(self, workflow_run_id: str) -> WorkflowRunRef:
532
- try:
533
- if not self.pooled_workflow_listener:
534
- self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
535
-
536
- return WorkflowRunRef(
445
+ return [
446
+ WorkflowRunRef(
537
447
  workflow_run_id=workflow_run_id,
538
448
  workflow_listener=self.pooled_workflow_listener,
539
449
  workflow_run_event_listener=self.listener_client,
540
450
  )
541
- except grpc.RpcError as e:
542
- raise ValueError(f"Could not get workflow run: {e}")
451
+ for workflow_run_id in resp.workflow_run_ids
452
+ ]
453
+
454
+ def get_workflow_run(self, workflow_run_id: str) -> WorkflowRunRef:
455
+ if not self.pooled_workflow_listener:
456
+ self.pooled_workflow_listener = PooledWorkflowRunListener(self.config)
457
+
458
+ return WorkflowRunRef(
459
+ workflow_run_id=workflow_run_id,
460
+ workflow_listener=self.pooled_workflow_listener,
461
+ workflow_run_event_listener=self.listener_client,
462
+ )