hatchet-sdk 0.46.1__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +77 -64
- hatchet_sdk/config.py +117 -0
- hatchet_sdk/connection.py +27 -13
- hatchet_sdk/context/__init__.py +0 -1
- hatchet_sdk/context/context.py +143 -202
- 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 +112 -35
- 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/{loader.py → v0/loader.py} +11 -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 +37 -59
- 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 +14 -25
- {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/METADATA +3 -2
- hatchet_sdk-1.0.0.dist-info/RECORD +485 -0
- {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/entry_points.txt +1 -0
- hatchet_sdk/utils/serialization.py +0 -18
- hatchet_sdk-0.46.1.dist-info/RECORD +0 -237
- /hatchet_sdk/{utils → v0/utils}/types.py +0 -0
- {hatchet_sdk-0.46.1.dist-info → hatchet_sdk-1.0.0.dist-info}/WHEEL +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import json
|
|
3
|
-
from
|
|
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,42 +45,53 @@ class _Subscription:
|
|
|
45
45
|
|
|
46
46
|
return event
|
|
47
47
|
|
|
48
|
-
async def put(self, item: WorkflowRunEvent):
|
|
48
|
+
async def put(self, item: WorkflowRunEvent) -> None:
|
|
49
49
|
await self.queue.put(item)
|
|
50
50
|
|
|
51
|
-
async def close(self):
|
|
51
|
+
async def close(self) -> None:
|
|
52
52
|
await self.queue.put(None)
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class PooledWorkflowRunListener:
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
def __init__(self, config: ClientConfig):
|
|
57
|
+
try:
|
|
58
|
+
asyncio.get_running_loop()
|
|
59
|
+
except RuntimeError:
|
|
60
|
+
loop = asyncio.new_event_loop()
|
|
61
|
+
asyncio.set_event_loop(loop)
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
conn = new_conn(config, True)
|
|
64
|
+
self.client = DispatcherStub(conn) # type: ignore[no-untyped-call]
|
|
65
|
+
self.token = config.token
|
|
66
|
+
self.config = config
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
# list of all active subscriptions, mapping from a subscription id to a workflow run id
|
|
69
|
+
self.subscriptions_to_workflows: dict[int, str] = {}
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
# list of workflow run ids mapped to an array of subscription ids
|
|
72
|
+
self.workflows_to_subscriptions: dict[str, list[int]] = {}
|
|
66
73
|
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
self.subscription_counter: int = 0
|
|
75
|
+
self.subscription_counter_lock: asyncio.Lock = asyncio.Lock()
|
|
69
76
|
|
|
70
|
-
|
|
77
|
+
self.requests: asyncio.Queue[SubscribeToWorkflowRunsRequest | int] = (
|
|
78
|
+
asyncio.Queue()
|
|
79
|
+
)
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
self.listener: (
|
|
82
|
+
grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]
|
|
83
|
+
| None
|
|
84
|
+
) = None
|
|
85
|
+
self.listener_task: asyncio.Task[None] | None = None
|
|
74
86
|
|
|
75
|
-
|
|
87
|
+
self.curr_requester: int = 0
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
self.
|
|
81
|
-
self.config = config
|
|
89
|
+
# events have keys of the format workflow_run_id + subscription_id
|
|
90
|
+
self.events: dict[int, _Subscription] = {}
|
|
91
|
+
|
|
92
|
+
self.interrupter: asyncio.Task[None] | None = None
|
|
82
93
|
|
|
83
|
-
async def _interrupter(self):
|
|
94
|
+
async def _interrupter(self) -> None:
|
|
84
95
|
"""
|
|
85
96
|
_interrupter runs in a separate thread and interrupts the listener according to a configurable duration.
|
|
86
97
|
"""
|
|
@@ -89,7 +100,7 @@ class PooledWorkflowRunListener:
|
|
|
89
100
|
if self.interrupt is not None:
|
|
90
101
|
self.interrupt.set()
|
|
91
102
|
|
|
92
|
-
async def _init_producer(self):
|
|
103
|
+
async def _init_producer(self) -> None:
|
|
93
104
|
try:
|
|
94
105
|
if not self.listener:
|
|
95
106
|
while True:
|
|
@@ -105,7 +116,10 @@ class PooledWorkflowRunListener:
|
|
|
105
116
|
self.interrupter = asyncio.create_task(self._interrupter())
|
|
106
117
|
|
|
107
118
|
while True:
|
|
108
|
-
self.interrupt =
|
|
119
|
+
self.interrupt = ThreadSafeEvent()
|
|
120
|
+
if self.listener is None:
|
|
121
|
+
continue
|
|
122
|
+
|
|
109
123
|
t = asyncio.create_task(
|
|
110
124
|
read_with_interrupt(self.listener, self.interrupt)
|
|
111
125
|
)
|
|
@@ -118,7 +132,8 @@ class PooledWorkflowRunListener:
|
|
|
118
132
|
)
|
|
119
133
|
|
|
120
134
|
t.cancel()
|
|
121
|
-
self.listener
|
|
135
|
+
if self.listener:
|
|
136
|
+
self.listener.cancel()
|
|
122
137
|
await asyncio.sleep(
|
|
123
138
|
DEFAULT_WORKFLOW_LISTENER_RETRY_INTERVAL
|
|
124
139
|
)
|
|
@@ -130,7 +145,7 @@ class PooledWorkflowRunListener:
|
|
|
130
145
|
break
|
|
131
146
|
|
|
132
147
|
# get a list of subscriptions for this workflow
|
|
133
|
-
subscriptions = self.
|
|
148
|
+
subscriptions = self.workflows_to_subscriptions.get(
|
|
134
149
|
workflow_event.workflowRunId, []
|
|
135
150
|
)
|
|
136
151
|
|
|
@@ -157,7 +172,7 @@ class PooledWorkflowRunListener:
|
|
|
157
172
|
self.curr_requester = self.curr_requester + 1
|
|
158
173
|
|
|
159
174
|
# replay all existing subscriptions
|
|
160
|
-
workflow_run_set = set(self.
|
|
175
|
+
workflow_run_set = set(self.subscriptions_to_workflows.values())
|
|
161
176
|
|
|
162
177
|
for workflow_run_id in workflow_run_set:
|
|
163
178
|
yield SubscribeToWorkflowRunsRequest(
|
|
@@ -178,17 +193,16 @@ class PooledWorkflowRunListener:
|
|
|
178
193
|
yield request
|
|
179
194
|
self.requests.task_done()
|
|
180
195
|
|
|
181
|
-
def cleanup_subscription(self, subscription_id: int):
|
|
182
|
-
workflow_run_id = self.
|
|
196
|
+
def cleanup_subscription(self, subscription_id: int) -> None:
|
|
197
|
+
workflow_run_id = self.subscriptions_to_workflows[subscription_id]
|
|
183
198
|
|
|
184
|
-
if workflow_run_id in self.
|
|
185
|
-
self.
|
|
199
|
+
if workflow_run_id in self.workflows_to_subscriptions:
|
|
200
|
+
self.workflows_to_subscriptions[workflow_run_id].remove(subscription_id)
|
|
186
201
|
|
|
187
|
-
del self.
|
|
202
|
+
del self.subscriptions_to_workflows[subscription_id]
|
|
188
203
|
del self.events[subscription_id]
|
|
189
204
|
|
|
190
|
-
async def subscribe(self, workflow_run_id: str):
|
|
191
|
-
init_producer: asyncio.Task = None
|
|
205
|
+
async def subscribe(self, workflow_run_id: str) -> WorkflowRunEvent:
|
|
192
206
|
try:
|
|
193
207
|
# create a new subscription id, place a mutex on the counter
|
|
194
208
|
await self.subscription_counter_lock.acquire()
|
|
@@ -196,12 +210,12 @@ class PooledWorkflowRunListener:
|
|
|
196
210
|
subscription_id = self.subscription_counter
|
|
197
211
|
self.subscription_counter_lock.release()
|
|
198
212
|
|
|
199
|
-
self.
|
|
213
|
+
self.subscriptions_to_workflows[subscription_id] = workflow_run_id
|
|
200
214
|
|
|
201
|
-
if workflow_run_id not in self.
|
|
202
|
-
self.
|
|
215
|
+
if workflow_run_id not in self.workflows_to_subscriptions:
|
|
216
|
+
self.workflows_to_subscriptions[workflow_run_id] = [subscription_id]
|
|
203
217
|
else:
|
|
204
|
-
self.
|
|
218
|
+
self.workflows_to_subscriptions[workflow_run_id].append(subscription_id)
|
|
205
219
|
|
|
206
220
|
self.events[subscription_id] = _Subscription(
|
|
207
221
|
subscription_id, workflow_run_id
|
|
@@ -216,23 +230,17 @@ class PooledWorkflowRunListener:
|
|
|
216
230
|
if not self.listener_task or self.listener_task.done():
|
|
217
231
|
self.listener_task = asyncio.create_task(self._init_producer())
|
|
218
232
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return event
|
|
233
|
+
return await self.events[subscription_id].get()
|
|
222
234
|
except asyncio.CancelledError:
|
|
223
235
|
raise
|
|
224
236
|
finally:
|
|
225
237
|
self.cleanup_subscription(subscription_id)
|
|
226
238
|
|
|
227
|
-
async def result(self, workflow_run_id: str):
|
|
239
|
+
async def result(self, workflow_run_id: str) -> dict[str, Any]:
|
|
228
240
|
from hatchet_sdk.clients.admin import DedupeViolationErr
|
|
229
241
|
|
|
230
242
|
event = await self.subscribe(workflow_run_id)
|
|
231
|
-
|
|
232
|
-
errors = []
|
|
233
|
-
|
|
234
|
-
if event.results:
|
|
235
|
-
errors = [result.error for result in event.results if result.error]
|
|
243
|
+
errors = [result.error for result in event.results if result.error]
|
|
236
244
|
|
|
237
245
|
if errors:
|
|
238
246
|
if DEDUPE_MESSAGE in errors[0]:
|
|
@@ -240,15 +248,15 @@ class PooledWorkflowRunListener:
|
|
|
240
248
|
else:
|
|
241
249
|
raise Exception(f"Workflow Errors: {errors}")
|
|
242
250
|
|
|
243
|
-
|
|
251
|
+
return {
|
|
244
252
|
result.stepReadableId: json.loads(result.output)
|
|
245
253
|
for result in event.results
|
|
246
254
|
if result.output
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
async def _retry_subscribe(
|
|
258
|
+
self,
|
|
259
|
+
) -> grpc.aio.UnaryStreamCall[SubscribeToWorkflowRunsRequest, WorkflowRunEvent]:
|
|
252
260
|
retries = 0
|
|
253
261
|
|
|
254
262
|
while retries < DEFAULT_WORKFLOW_LISTENER_RETRY_COUNT:
|
|
@@ -260,14 +268,19 @@ class PooledWorkflowRunListener:
|
|
|
260
268
|
if self.curr_requester != 0:
|
|
261
269
|
self.requests.put_nowait(self.curr_requester)
|
|
262
270
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
271
|
+
return cast(
|
|
272
|
+
grpc.aio.UnaryStreamCall[
|
|
273
|
+
SubscribeToWorkflowRunsRequest, WorkflowRunEvent
|
|
274
|
+
],
|
|
275
|
+
self.client.SubscribeToWorkflowRuns(
|
|
276
|
+
self._request(),
|
|
277
|
+
metadata=get_metadata(self.token),
|
|
278
|
+
),
|
|
266
279
|
)
|
|
267
|
-
|
|
268
|
-
return listener
|
|
269
280
|
except grpc.RpcError as e:
|
|
270
281
|
if e.code() == grpc.StatusCode.UNAVAILABLE:
|
|
271
282
|
retries = retries + 1
|
|
272
283
|
else:
|
|
273
284
|
raise ValueError(f"gRPC error: {e}")
|
|
285
|
+
|
|
286
|
+
raise ValueError("Failed to connect to workflow run listener")
|
hatchet_sdk/config.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from logging import Logger, getLogger
|
|
3
|
+
|
|
4
|
+
from pydantic import Field, field_validator, model_validator
|
|
5
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
|
+
|
|
7
|
+
from hatchet_sdk.token import get_addresses_from_jwt, get_tenant_id_from_jwt
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_settings_config(env_prefix: str) -> SettingsConfigDict:
|
|
11
|
+
return SettingsConfigDict(
|
|
12
|
+
env_prefix=env_prefix,
|
|
13
|
+
env_file=(".env", ".env.hatchet", ".env.dev", ".env.local"),
|
|
14
|
+
extra="ignore",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ClientTLSConfig(BaseSettings):
|
|
19
|
+
model_config = create_settings_config(
|
|
20
|
+
env_prefix="HATCHET_CLIENT_TLS_",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
strategy: str = "tls"
|
|
24
|
+
cert_file: str | None = None
|
|
25
|
+
key_file: str | None = None
|
|
26
|
+
root_ca_file: str | None = None
|
|
27
|
+
server_name: str = ""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class HealthcheckConfig(BaseSettings):
|
|
31
|
+
model_config = create_settings_config(
|
|
32
|
+
env_prefix="HATCHET_CLIENT_WORKER_HEALTHCHECK_",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
port: int = 8001
|
|
36
|
+
enabled: bool = False
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
DEFAULT_HOST_PORT = "localhost:7070"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class ClientConfig(BaseSettings):
|
|
43
|
+
model_config = create_settings_config(
|
|
44
|
+
env_prefix="HATCHET_CLIENT_",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
token: str = ""
|
|
48
|
+
logger: Logger = getLogger()
|
|
49
|
+
|
|
50
|
+
tenant_id: str = ""
|
|
51
|
+
host_port: str = DEFAULT_HOST_PORT
|
|
52
|
+
server_url: str = "https://app.dev.hatchet-tools.com"
|
|
53
|
+
namespace: str = ""
|
|
54
|
+
|
|
55
|
+
tls_config: ClientTLSConfig = Field(default_factory=lambda: ClientTLSConfig())
|
|
56
|
+
healthcheck: HealthcheckConfig = Field(default_factory=lambda: HealthcheckConfig())
|
|
57
|
+
|
|
58
|
+
listener_v2_timeout: int | None = None
|
|
59
|
+
grpc_max_recv_message_length: int = Field(
|
|
60
|
+
default=4 * 1024 * 1024, description="4MB default"
|
|
61
|
+
)
|
|
62
|
+
grpc_max_send_message_length: int = Field(
|
|
63
|
+
default=4 * 1024 * 1024, description="4MB default"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
worker_preset_labels: dict[str, str] = Field(default_factory=dict)
|
|
67
|
+
enable_force_kill_sync_threads: bool = False
|
|
68
|
+
|
|
69
|
+
@model_validator(mode="after")
|
|
70
|
+
def validate_token_and_tenant(self) -> "ClientConfig":
|
|
71
|
+
if not self.token:
|
|
72
|
+
raise ValueError("Token must be set")
|
|
73
|
+
|
|
74
|
+
if not self.tenant_id:
|
|
75
|
+
self.tenant_id = get_tenant_id_from_jwt(self.token)
|
|
76
|
+
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
@model_validator(mode="after")
|
|
80
|
+
def validate_addresses(self) -> "ClientConfig":
|
|
81
|
+
if self.host_port == DEFAULT_HOST_PORT:
|
|
82
|
+
server_url, grpc_broadcast_address = get_addresses_from_jwt(self.token)
|
|
83
|
+
self.host_port = grpc_broadcast_address
|
|
84
|
+
self.server_url = server_url
|
|
85
|
+
else:
|
|
86
|
+
self.server_url = self.host_port
|
|
87
|
+
|
|
88
|
+
if not self.tls_config.server_name:
|
|
89
|
+
self.tls_config.server_name = self.host_port.split(":")[0]
|
|
90
|
+
|
|
91
|
+
if not self.tls_config.server_name:
|
|
92
|
+
self.tls_config.server_name = "localhost"
|
|
93
|
+
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
@field_validator("listener_v2_timeout")
|
|
97
|
+
@classmethod
|
|
98
|
+
def validate_listener_timeout(cls, value: int | None | str) -> int | None:
|
|
99
|
+
if value is None:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
if isinstance(value, int):
|
|
103
|
+
return value
|
|
104
|
+
|
|
105
|
+
return int(value)
|
|
106
|
+
|
|
107
|
+
@field_validator("namespace")
|
|
108
|
+
@classmethod
|
|
109
|
+
def validate_namespace(cls, namespace: str) -> str:
|
|
110
|
+
if not namespace:
|
|
111
|
+
return ""
|
|
112
|
+
if not namespace.endswith("_"):
|
|
113
|
+
namespace = f"{namespace}_"
|
|
114
|
+
return namespace.lower()
|
|
115
|
+
|
|
116
|
+
def __hash__(self) -> int:
|
|
117
|
+
return hash(json.dumps(self.model_dump(), default=str))
|