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