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.
- hatchet_sdk/__init__.py +45 -25
- hatchet_sdk/client.py +19 -94
- hatchet_sdk/clients/admin.py +309 -389
- hatchet_sdk/clients/dispatcher/action_listener.py +131 -109
- hatchet_sdk/clients/dispatcher/dispatcher.py +39 -37
- hatchet_sdk/clients/durable_event_listener.py +327 -0
- hatchet_sdk/clients/event_ts.py +23 -10
- hatchet_sdk/clients/events.py +96 -99
- hatchet_sdk/clients/rest/__init__.py +35 -0
- hatchet_sdk/clients/rest/api/__init__.py +2 -0
- hatchet_sdk/clients/rest/api/log_api.py +258 -0
- hatchet_sdk/clients/rest/api/task_api.py +2200 -0
- hatchet_sdk/clients/rest/api/workflow_runs_api.py +1274 -116
- 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 +33 -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_log_line.py +94 -0
- hatchet_sdk/clients/rest/models/v1_log_line_level.py +39 -0
- hatchet_sdk/clients/rest/models/v1_log_line_list.py +110 -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 +228 -0
- hatchet_sdk/clients/rest/models/v1_task_summary_list.py +110 -0
- hatchet_sdk/clients/rest/models/v1_trigger_workflow_run_request.py +95 -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_run_display_name.py +98 -0
- hatchet_sdk/clients/rest/models/v1_workflow_run_display_name_list.py +114 -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 +104 -0
- hatchet_sdk/clients/rest/rest.py +37 -26
- hatchet_sdk/clients/rest/tenacity_utils.py +1 -1
- hatchet_sdk/clients/rest_client.py +153 -116
- hatchet_sdk/clients/run_event_listener.py +65 -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 -280
- hatchet_sdk/contracts/dispatcher_pb2_grpc.py +1 -1
- hatchet_sdk/contracts/events_pb2.py +2 -2
- hatchet_sdk/contracts/events_pb2_grpc.py +1 -1
- hatchet_sdk/contracts/v1/dispatcher_pb2.py +36 -0
- hatchet_sdk/contracts/v1/dispatcher_pb2.pyi +38 -0
- hatchet_sdk/contracts/v1/dispatcher_pb2_grpc.py +145 -0
- hatchet_sdk/contracts/v1/shared/condition_pb2.py +39 -0
- hatchet_sdk/contracts/v1/shared/condition_pb2.pyi +72 -0
- hatchet_sdk/contracts/v1/shared/condition_pb2_grpc.py +29 -0
- hatchet_sdk/contracts/v1/workflows_pb2.py +67 -0
- hatchet_sdk/contracts/v1/workflows_pb2.pyi +228 -0
- hatchet_sdk/contracts/v1/workflows_pb2_grpc.py +234 -0
- hatchet_sdk/contracts/workflows_pb2_grpc.py +1 -1
- hatchet_sdk/features/cron.py +43 -57
- hatchet_sdk/features/scheduled.py +60 -74
- hatchet_sdk/hatchet.py +491 -218
- hatchet_sdk/labels.py +4 -6
- hatchet_sdk/metadata.py +1 -1
- hatchet_sdk/opentelemetry/instrumentor.py +17 -18
- hatchet_sdk/rate_limit.py +40 -55
- hatchet_sdk/runnables/contextvars.py +12 -0
- hatchet_sdk/runnables/standalone.py +194 -0
- hatchet_sdk/runnables/task.py +144 -0
- hatchet_sdk/runnables/types.py +138 -0
- hatchet_sdk/runnables/workflow.py +764 -0
- hatchet_sdk/token.py +13 -9
- hatchet_sdk/utils/aio_utils.py +0 -119
- hatchet_sdk/utils/proto_enums.py +47 -0
- hatchet_sdk/utils/timedelta_to_expression.py +23 -0
- hatchet_sdk/utils/typing.py +10 -2
- 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 +622 -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/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 +294 -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/worker.py +391 -0
- hatchet_sdk/{workflow.py → v0/workflow.py} +4 -4
- hatchet_sdk/v0/workflow_run.py +59 -0
- hatchet_sdk/waits.py +120 -0
- hatchet_sdk/worker/__init__.py +0 -1
- hatchet_sdk/worker/action_listener_process.py +80 -55
- hatchet_sdk/worker/runner/run_loop_manager.py +46 -34
- hatchet_sdk/worker/runner/runner.py +82 -87
- hatchet_sdk/worker/runner/utils/capture_logs.py +26 -23
- hatchet_sdk/worker/worker.py +172 -149
- hatchet_sdk/workflow_run.py +7 -21
- {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.dist-info}/METADATA +2 -2
- hatchet_sdk-1.0.0a1.dist-info/RECORD +505 -0
- {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.dist-info}/entry_points.txt +2 -0
- hatchet_sdk/utils/serialization.py +0 -18
- hatchet_sdk-0.47.1.dist-info/RECORD +0 -237
- /hatchet_sdk/{loader.py → v0/loader.py} +0 -0
- /hatchet_sdk/{semver.py → v0/semver.py} +0 -0
- /hatchet_sdk/{utils → v0/utils}/types.py +0 -0
- /hatchet_sdk/{worker → v0/worker}/runner/utils/error_with_traceback.py +0 -0
- {hatchet_sdk-0.47.1.dist-info → hatchet_sdk-1.0.0a1.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:
|
|
@@ -146,14 +133,16 @@ class RunEventListener:
|
|
|
146
133
|
try:
|
|
147
134
|
if workflow_event.eventPayload:
|
|
148
135
|
payload = json.loads(workflow_event.eventPayload)
|
|
149
|
-
except Exception
|
|
136
|
+
except Exception:
|
|
150
137
|
payload = workflow_event.eventPayload
|
|
151
138
|
pass
|
|
152
139
|
|
|
140
|
+
assert isinstance(payload, str)
|
|
141
|
+
|
|
153
142
|
yield StepRunEvent(type=eventType, payload=payload)
|
|
154
143
|
elif workflow_event.resourceType == RESOURCE_TYPE_WORKFLOW_RUN:
|
|
155
|
-
if workflow_event.eventType in
|
|
156
|
-
|
|
144
|
+
if workflow_event.eventType in step_run_event_type_mapping:
|
|
145
|
+
workflowRunEventType = step_run_event_type_mapping[
|
|
157
146
|
workflow_event.eventType
|
|
158
147
|
]
|
|
159
148
|
else:
|
|
@@ -166,10 +155,12 @@ class RunEventListener:
|
|
|
166
155
|
try:
|
|
167
156
|
if workflow_event.eventPayload:
|
|
168
157
|
payload = json.loads(workflow_event.eventPayload)
|
|
169
|
-
except Exception
|
|
158
|
+
except Exception:
|
|
170
159
|
pass
|
|
171
160
|
|
|
172
|
-
|
|
161
|
+
assert isinstance(payload, str)
|
|
162
|
+
|
|
163
|
+
yield StepRunEvent(type=workflowRunEventType, payload=payload)
|
|
173
164
|
|
|
174
165
|
if workflow_event.hangup:
|
|
175
166
|
listener = None
|
|
@@ -194,7 +185,7 @@ class RunEventListener:
|
|
|
194
185
|
break
|
|
195
186
|
# Raise StopAsyncIteration to properly end the generator
|
|
196
187
|
|
|
197
|
-
async def retry_subscribe(self):
|
|
188
|
+
async def retry_subscribe(self) -> AsyncGenerator[WorkflowEvent, None]:
|
|
198
189
|
retries = 0
|
|
199
190
|
|
|
200
191
|
while retries < DEFAULT_ACTION_LISTENER_RETRY_COUNT:
|
|
@@ -203,19 +194,25 @@ class RunEventListener:
|
|
|
203
194
|
await asyncio.sleep(DEFAULT_ACTION_LISTENER_RETRY_INTERVAL)
|
|
204
195
|
|
|
205
196
|
if self.workflow_run_id is not None:
|
|
206
|
-
return
|
|
207
|
-
|
|
208
|
-
|
|
197
|
+
return cast(
|
|
198
|
+
AsyncGenerator[WorkflowEvent, None],
|
|
199
|
+
self.client.SubscribeToWorkflowEvents(
|
|
200
|
+
SubscribeToWorkflowEventsRequest(
|
|
201
|
+
workflowRunId=self.workflow_run_id,
|
|
202
|
+
),
|
|
203
|
+
metadata=get_metadata(self.token),
|
|
209
204
|
),
|
|
210
|
-
metadata=get_metadata(self.token),
|
|
211
205
|
)
|
|
212
206
|
elif self.additional_meta_kv is not None:
|
|
213
|
-
return
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
return cast(
|
|
208
|
+
AsyncGenerator[WorkflowEvent, None],
|
|
209
|
+
self.client.SubscribeToWorkflowEvents(
|
|
210
|
+
SubscribeToWorkflowEventsRequest(
|
|
211
|
+
additionalMetaKey=self.additional_meta_kv[0],
|
|
212
|
+
additionalMetaValue=self.additional_meta_kv[1],
|
|
213
|
+
),
|
|
214
|
+
metadata=get_metadata(self.token),
|
|
217
215
|
),
|
|
218
|
-
metadata=get_metadata(self.token),
|
|
219
216
|
)
|
|
220
217
|
else:
|
|
221
218
|
raise Exception("no listener method provided")
|
|
@@ -226,34 +223,42 @@ class RunEventListener:
|
|
|
226
223
|
else:
|
|
227
224
|
raise ValueError(f"gRPC error: {e}")
|
|
228
225
|
|
|
226
|
+
raise Exception("Failed to subscribe to workflow events")
|
|
227
|
+
|
|
229
228
|
|
|
230
229
|
class RunEventListenerClient:
|
|
231
230
|
def __init__(self, config: ClientConfig):
|
|
232
231
|
self.token = config.token
|
|
233
232
|
self.config = config
|
|
234
|
-
self.client: DispatcherStub = None
|
|
233
|
+
self.client: DispatcherStub | None = None
|
|
235
234
|
|
|
236
|
-
def stream_by_run_id(self, workflow_run_id: str):
|
|
235
|
+
def stream_by_run_id(self, workflow_run_id: str) -> RunEventListener:
|
|
237
236
|
return self.stream(workflow_run_id)
|
|
238
237
|
|
|
239
|
-
def stream(self, workflow_run_id: str):
|
|
238
|
+
def stream(self, workflow_run_id: str) -> RunEventListener:
|
|
240
239
|
if not isinstance(workflow_run_id, str) and hasattr(workflow_run_id, "__str__"):
|
|
241
240
|
workflow_run_id = str(workflow_run_id)
|
|
242
241
|
|
|
243
242
|
if not self.client:
|
|
244
243
|
aio_conn = new_conn(self.config, True)
|
|
245
|
-
self.client = DispatcherStub(aio_conn)
|
|
244
|
+
self.client = DispatcherStub(aio_conn) # type: ignore[no-untyped-call]
|
|
246
245
|
|
|
247
|
-
return RunEventListener
|
|
246
|
+
return RunEventListener(
|
|
247
|
+
client=self.client, token=self.token, workflow_run_id=workflow_run_id
|
|
248
|
+
)
|
|
248
249
|
|
|
249
|
-
def stream_by_additional_metadata(self, key: str, value: str):
|
|
250
|
+
def stream_by_additional_metadata(self, key: str, value: str) -> RunEventListener:
|
|
250
251
|
if not self.client:
|
|
251
252
|
aio_conn = new_conn(self.config, True)
|
|
252
|
-
self.client = DispatcherStub(aio_conn)
|
|
253
|
+
self.client = DispatcherStub(aio_conn) # type: ignore[no-untyped-call]
|
|
253
254
|
|
|
254
|
-
return RunEventListener
|
|
255
|
+
return RunEventListener(
|
|
256
|
+
client=self.client, token=self.token, additional_meta_kv=(key, value)
|
|
257
|
+
)
|
|
255
258
|
|
|
256
|
-
async def on(
|
|
259
|
+
async def on(
|
|
260
|
+
self, workflow_run_id: str, handler: Callable[[StepRunEvent], Any] | None = None
|
|
261
|
+
) -> None:
|
|
257
262
|
async for event in self.stream(workflow_run_id):
|
|
258
263
|
# call the handler if provided
|
|
259
264
|
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))
|