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
|
@@ -2,18 +2,23 @@ import asyncio
|
|
|
2
2
|
import json
|
|
3
3
|
import time
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
|
-
from
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Any, AsyncGenerator, Optional, cast
|
|
6
7
|
|
|
7
8
|
import grpc
|
|
8
|
-
|
|
9
|
+
import grpc.aio
|
|
10
|
+
from grpc._cython import cygrpc # type: ignore[attr-defined]
|
|
11
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
9
12
|
|
|
10
|
-
from hatchet_sdk.clients.event_ts import
|
|
13
|
+
from hatchet_sdk.clients.event_ts import ThreadSafeEvent, read_with_interrupt
|
|
14
|
+
from hatchet_sdk.clients.events import proto_timestamp_now
|
|
11
15
|
from hatchet_sdk.clients.run_event_listener import (
|
|
12
16
|
DEFAULT_ACTION_LISTENER_RETRY_INTERVAL,
|
|
13
17
|
)
|
|
18
|
+
from hatchet_sdk.config import ClientConfig
|
|
14
19
|
from hatchet_sdk.connection import new_conn
|
|
20
|
+
from hatchet_sdk.contracts.dispatcher_pb2 import ActionType as ActionTypeProto
|
|
15
21
|
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
16
|
-
ActionType,
|
|
17
22
|
AssignedAction,
|
|
18
23
|
HeartbeatRequest,
|
|
19
24
|
WorkerLabels,
|
|
@@ -22,31 +27,26 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
|
22
27
|
)
|
|
23
28
|
from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
|
|
24
29
|
from hatchet_sdk.logger import logger
|
|
30
|
+
from hatchet_sdk.metadata import get_metadata
|
|
25
31
|
from hatchet_sdk.utils.backoff import exp_backoff_sleep
|
|
26
|
-
from hatchet_sdk.utils.
|
|
27
|
-
|
|
28
|
-
from ...loader import ClientConfig
|
|
29
|
-
from ...metadata import get_metadata
|
|
30
|
-
from ..events import proto_timestamp_now
|
|
32
|
+
from hatchet_sdk.utils.proto_enums import convert_proto_enum_to_python
|
|
33
|
+
from hatchet_sdk.utils.typing import JSONSerializableMapping
|
|
31
34
|
|
|
32
35
|
DEFAULT_ACTION_TIMEOUT = 600 # seconds
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
DEFAULT_ACTION_LISTENER_RETRY_INTERVAL = 5 # seconds
|
|
36
36
|
DEFAULT_ACTION_LISTENER_RETRY_COUNT = 15
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
@dataclass
|
|
40
40
|
class GetActionListenerRequest:
|
|
41
41
|
worker_name: str
|
|
42
|
-
services:
|
|
43
|
-
actions:
|
|
44
|
-
max_runs:
|
|
42
|
+
services: list[str]
|
|
43
|
+
actions: list[str]
|
|
44
|
+
max_runs: int | None = None
|
|
45
45
|
_labels: dict[str, str | int] = field(default_factory=dict)
|
|
46
46
|
|
|
47
47
|
labels: dict[str, WorkerLabels] = field(init=False)
|
|
48
48
|
|
|
49
|
-
def __post_init__(self):
|
|
49
|
+
def __post_init__(self) -> None:
|
|
50
50
|
self.labels = {}
|
|
51
51
|
|
|
52
52
|
for key, value in self._labels.items():
|
|
@@ -56,8 +56,31 @@ class GetActionListenerRequest:
|
|
|
56
56
|
self.labels[key] = WorkerLabels(strValue=str(value))
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
class ActionPayload(BaseModel):
|
|
60
|
+
model_config = ConfigDict(extra="allow")
|
|
61
|
+
|
|
62
|
+
input: JSONSerializableMapping = Field(default_factory=dict)
|
|
63
|
+
parents: dict[str, JSONSerializableMapping] = Field(default_factory=dict)
|
|
64
|
+
overrides: JSONSerializableMapping = Field(default_factory=dict)
|
|
65
|
+
user_data: JSONSerializableMapping = Field(default_factory=dict)
|
|
66
|
+
step_run_errors: dict[str, str] = Field(default_factory=dict)
|
|
67
|
+
triggered_by: str | None = None
|
|
68
|
+
|
|
69
|
+
@field_validator(
|
|
70
|
+
"input", "parents", "overrides", "user_data", "step_run_errors", mode="before"
|
|
71
|
+
)
|
|
72
|
+
@classmethod
|
|
73
|
+
def validate_fields(cls, v: Any) -> Any:
|
|
74
|
+
return v or {}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ActionType(str, Enum):
|
|
78
|
+
START_STEP_RUN = "START_STEP_RUN"
|
|
79
|
+
CANCEL_STEP_RUN = "CANCEL_STEP_RUN"
|
|
80
|
+
START_GET_GROUP_KEY = "START_GET_GROUP_KEY"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Action(BaseModel):
|
|
61
84
|
worker_id: str
|
|
62
85
|
tenant_id: str
|
|
63
86
|
workflow_run_id: str
|
|
@@ -68,31 +91,25 @@ class Action:
|
|
|
68
91
|
step_id: str
|
|
69
92
|
step_run_id: str
|
|
70
93
|
action_id: str
|
|
71
|
-
action_payload: str
|
|
72
94
|
action_type: ActionType
|
|
73
95
|
retry_count: int
|
|
74
|
-
|
|
96
|
+
action_payload: ActionPayload
|
|
97
|
+
additional_metadata: JSONSerializableMapping = field(default_factory=dict)
|
|
75
98
|
|
|
76
99
|
child_workflow_index: int | None = None
|
|
77
100
|
child_workflow_key: str | None = None
|
|
78
101
|
parent_workflow_run_id: str | None = None
|
|
79
102
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# If JSON decoding fails, keep the original string
|
|
86
|
-
pass
|
|
87
|
-
|
|
88
|
-
# Ensure additional_metadata is always a dictionary
|
|
89
|
-
if not isinstance(self.additional_metadata, dict):
|
|
90
|
-
self.additional_metadata = {}
|
|
103
|
+
def _dump_payload_to_str(self) -> str:
|
|
104
|
+
try:
|
|
105
|
+
return json.dumps(self.action_payload.model_dump(), default=str)
|
|
106
|
+
except Exception:
|
|
107
|
+
return str(self.action_payload)
|
|
91
108
|
|
|
92
109
|
@property
|
|
93
110
|
def otel_attributes(self) -> dict[str, str | int]:
|
|
94
111
|
try:
|
|
95
|
-
payload_str = json.dumps(self.action_payload, default=str)
|
|
112
|
+
payload_str = json.dumps(self.action_payload.model_dump(), default=str)
|
|
96
113
|
except Exception:
|
|
97
114
|
payload_str = str(self.action_payload)
|
|
98
115
|
|
|
@@ -115,9 +132,14 @@ class Action:
|
|
|
115
132
|
return {k: v for k, v in attrs.items() if v}
|
|
116
133
|
|
|
117
134
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
135
|
+
def parse_additional_metadata(additional_metadata: str) -> JSONSerializableMapping:
|
|
136
|
+
try:
|
|
137
|
+
return cast(
|
|
138
|
+
JSONSerializableMapping,
|
|
139
|
+
json.loads(additional_metadata),
|
|
140
|
+
)
|
|
141
|
+
except json.JSONDecodeError:
|
|
142
|
+
return {}
|
|
121
143
|
|
|
122
144
|
|
|
123
145
|
@dataclass
|
|
@@ -132,22 +154,22 @@ class ActionListener:
|
|
|
132
154
|
last_connection_attempt: float = field(default=0, init=False)
|
|
133
155
|
last_heartbeat_succeeded: bool = field(default=True, init=False)
|
|
134
156
|
time_last_hb_succeeded: float = field(default=9999999999999, init=False)
|
|
135
|
-
heartbeat_task: Optional[asyncio.Task] = field(default=None, init=False)
|
|
157
|
+
heartbeat_task: Optional[asyncio.Task[None]] = field(default=None, init=False)
|
|
136
158
|
run_heartbeat: bool = field(default=True, init=False)
|
|
137
159
|
listen_strategy: str = field(default="v2", init=False)
|
|
138
160
|
stop_signal: bool = field(default=False, init=False)
|
|
139
161
|
|
|
140
162
|
missed_heartbeats: int = field(default=0, init=False)
|
|
141
163
|
|
|
142
|
-
def __post_init__(self):
|
|
143
|
-
self.client = DispatcherStub(new_conn(self.config))
|
|
144
|
-
self.aio_client = DispatcherStub(new_conn(self.config, True))
|
|
164
|
+
def __post_init__(self) -> None:
|
|
165
|
+
self.client = DispatcherStub(new_conn(self.config, False)) # type: ignore[no-untyped-call]
|
|
166
|
+
self.aio_client = DispatcherStub(new_conn(self.config, True)) # type: ignore[no-untyped-call]
|
|
145
167
|
self.token = self.config.token
|
|
146
168
|
|
|
147
|
-
def is_healthy(self):
|
|
169
|
+
def is_healthy(self) -> bool:
|
|
148
170
|
return self.last_heartbeat_succeeded
|
|
149
171
|
|
|
150
|
-
async def heartbeat(self):
|
|
172
|
+
async def heartbeat(self) -> None:
|
|
151
173
|
# send a heartbeat every 4 seconds
|
|
152
174
|
heartbeat_delay = 4
|
|
153
175
|
|
|
@@ -207,7 +229,7 @@ class ActionListener:
|
|
|
207
229
|
break
|
|
208
230
|
await asyncio.sleep(heartbeat_delay)
|
|
209
231
|
|
|
210
|
-
async def start_heartbeater(self):
|
|
232
|
+
async def start_heartbeater(self) -> None:
|
|
211
233
|
if self.heartbeat_task is not None:
|
|
212
234
|
return
|
|
213
235
|
|
|
@@ -221,10 +243,10 @@ class ActionListener:
|
|
|
221
243
|
raise e
|
|
222
244
|
self.heartbeat_task = loop.create_task(self.heartbeat())
|
|
223
245
|
|
|
224
|
-
def __aiter__(self):
|
|
246
|
+
def __aiter__(self) -> AsyncGenerator[Action | None, None]:
|
|
225
247
|
return self._generator()
|
|
226
248
|
|
|
227
|
-
async def _generator(self) -> AsyncGenerator[Action, None]:
|
|
249
|
+
async def _generator(self) -> AsyncGenerator[Action | None, None]:
|
|
228
250
|
listener = None
|
|
229
251
|
|
|
230
252
|
while not self.stop_signal:
|
|
@@ -239,7 +261,11 @@ class ActionListener:
|
|
|
239
261
|
|
|
240
262
|
try:
|
|
241
263
|
while not self.stop_signal:
|
|
242
|
-
self.interrupt =
|
|
264
|
+
self.interrupt = ThreadSafeEvent()
|
|
265
|
+
|
|
266
|
+
if listener is None:
|
|
267
|
+
continue
|
|
268
|
+
|
|
243
269
|
t = asyncio.create_task(
|
|
244
270
|
read_with_interrupt(listener, self.interrupt)
|
|
245
271
|
)
|
|
@@ -252,7 +278,10 @@ class ActionListener:
|
|
|
252
278
|
)
|
|
253
279
|
|
|
254
280
|
t.cancel()
|
|
255
|
-
|
|
281
|
+
|
|
282
|
+
if listener:
|
|
283
|
+
listener.cancel()
|
|
284
|
+
|
|
256
285
|
break
|
|
257
286
|
|
|
258
287
|
assigned_action = t.result()
|
|
@@ -262,20 +291,12 @@ class ActionListener:
|
|
|
262
291
|
break
|
|
263
292
|
|
|
264
293
|
self.retries = 0
|
|
265
|
-
assigned_action: AssignedAction
|
|
266
|
-
|
|
267
|
-
# Process the received action
|
|
268
|
-
action_type = self.map_action_type(assigned_action.actionType)
|
|
269
294
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
else:
|
|
276
|
-
action_payload = self.parse_action_payload(
|
|
277
|
-
assigned_action.actionPayload
|
|
278
|
-
)
|
|
295
|
+
action_payload = (
|
|
296
|
+
{}
|
|
297
|
+
if not assigned_action.actionPayload
|
|
298
|
+
else self.parse_action_payload(assigned_action.actionPayload)
|
|
299
|
+
)
|
|
279
300
|
|
|
280
301
|
action = Action(
|
|
281
302
|
tenant_id=assigned_action.tenantId,
|
|
@@ -288,10 +309,16 @@ class ActionListener:
|
|
|
288
309
|
step_id=assigned_action.stepId,
|
|
289
310
|
step_run_id=assigned_action.stepRunId,
|
|
290
311
|
action_id=assigned_action.actionId,
|
|
291
|
-
action_payload=action_payload,
|
|
292
|
-
action_type=
|
|
312
|
+
action_payload=ActionPayload.model_validate(action_payload),
|
|
313
|
+
action_type=convert_proto_enum_to_python(
|
|
314
|
+
assigned_action.actionType,
|
|
315
|
+
ActionType,
|
|
316
|
+
ActionTypeProto,
|
|
317
|
+
),
|
|
293
318
|
retry_count=assigned_action.retryCount,
|
|
294
|
-
additional_metadata=
|
|
319
|
+
additional_metadata=parse_additional_metadata(
|
|
320
|
+
assigned_action.additional_metadata
|
|
321
|
+
),
|
|
295
322
|
child_workflow_index=assigned_action.child_workflow_index,
|
|
296
323
|
child_workflow_key=assigned_action.child_workflow_key,
|
|
297
324
|
parent_workflow_run_id=assigned_action.parent_workflow_run_id,
|
|
@@ -325,25 +352,15 @@ class ActionListener:
|
|
|
325
352
|
|
|
326
353
|
self.retries = self.retries + 1
|
|
327
354
|
|
|
328
|
-
def parse_action_payload(self, payload: str):
|
|
355
|
+
def parse_action_payload(self, payload: str) -> JSONSerializableMapping:
|
|
329
356
|
try:
|
|
330
|
-
|
|
357
|
+
return cast(JSONSerializableMapping, json.loads(payload))
|
|
331
358
|
except json.JSONDecodeError as e:
|
|
332
359
|
raise ValueError(f"Error decoding payload: {e}")
|
|
333
|
-
return payload_data
|
|
334
|
-
|
|
335
|
-
def map_action_type(self, action_type):
|
|
336
|
-
if action_type == ActionType.START_STEP_RUN:
|
|
337
|
-
return START_STEP_RUN
|
|
338
|
-
elif action_type == ActionType.CANCEL_STEP_RUN:
|
|
339
|
-
return CANCEL_STEP_RUN
|
|
340
|
-
elif action_type == ActionType.START_GET_GROUP_KEY:
|
|
341
|
-
return START_GET_GROUP_KEY
|
|
342
|
-
else:
|
|
343
|
-
# logger.error(f"Unknown action type: {action_type}")
|
|
344
|
-
return None
|
|
345
360
|
|
|
346
|
-
async def get_listen_client(
|
|
361
|
+
async def get_listen_client(
|
|
362
|
+
self,
|
|
363
|
+
) -> grpc.aio.UnaryStreamCall[WorkerListenRequest, AssignedAction]:
|
|
347
364
|
current_time = int(time.time())
|
|
348
365
|
|
|
349
366
|
if (
|
|
@@ -371,7 +388,7 @@ class ActionListener:
|
|
|
371
388
|
f"action listener connection interrupted, retrying... ({self.retries}/{DEFAULT_ACTION_LISTENER_RETRY_COUNT})"
|
|
372
389
|
)
|
|
373
390
|
|
|
374
|
-
self.aio_client = DispatcherStub(new_conn(self.config, True))
|
|
391
|
+
self.aio_client = DispatcherStub(new_conn(self.config, True)) # type: ignore[no-untyped-call]
|
|
375
392
|
|
|
376
393
|
if self.listen_strategy == "v2":
|
|
377
394
|
# we should await for the listener to be established before
|
|
@@ -392,11 +409,14 @@ class ActionListener:
|
|
|
392
409
|
|
|
393
410
|
self.last_connection_attempt = current_time
|
|
394
411
|
|
|
395
|
-
return
|
|
412
|
+
return cast(
|
|
413
|
+
grpc.aio.UnaryStreamCall[WorkerListenRequest, AssignedAction], listener
|
|
414
|
+
)
|
|
396
415
|
|
|
397
|
-
def cleanup(self):
|
|
416
|
+
def cleanup(self) -> None:
|
|
398
417
|
self.run_heartbeat = False
|
|
399
|
-
self.heartbeat_task
|
|
418
|
+
if self.heartbeat_task is not None:
|
|
419
|
+
self.heartbeat_task.cancel()
|
|
400
420
|
|
|
401
421
|
try:
|
|
402
422
|
self.unregister()
|
|
@@ -406,9 +426,11 @@ class ActionListener:
|
|
|
406
426
|
if self.interrupt:
|
|
407
427
|
self.interrupt.set()
|
|
408
428
|
|
|
409
|
-
def unregister(self):
|
|
429
|
+
def unregister(self) -> WorkerUnsubscribeRequest:
|
|
410
430
|
self.run_heartbeat = False
|
|
411
|
-
|
|
431
|
+
|
|
432
|
+
if self.heartbeat_task is not None:
|
|
433
|
+
self.heartbeat_task.cancel()
|
|
412
434
|
|
|
413
435
|
try:
|
|
414
436
|
req = self.aio_client.Unsubscribe(
|
|
@@ -418,6 +440,6 @@ class ActionListener:
|
|
|
418
440
|
)
|
|
419
441
|
if self.interrupt is not None:
|
|
420
442
|
self.interrupt.set()
|
|
421
|
-
return req
|
|
443
|
+
return cast(WorkerUnsubscribeRequest, req)
|
|
422
444
|
except grpc.RpcError as e:
|
|
423
445
|
raise Exception(f"Failed to unsubscribe: {e}")
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import cast
|
|
2
2
|
|
|
3
|
+
import grpc.aio
|
|
3
4
|
from google.protobuf.timestamp_pb2 import Timestamp
|
|
4
5
|
|
|
5
6
|
from hatchet_sdk.clients.dispatcher.action_listener import (
|
|
@@ -8,6 +9,7 @@ from hatchet_sdk.clients.dispatcher.action_listener import (
|
|
|
8
9
|
GetActionListenerRequest,
|
|
9
10
|
)
|
|
10
11
|
from hatchet_sdk.clients.rest.tenacity_utils import tenacity_retry
|
|
12
|
+
from hatchet_sdk.config import ClientConfig
|
|
11
13
|
from hatchet_sdk.connection import new_conn
|
|
12
14
|
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
13
15
|
STEP_EVENT_TYPE_COMPLETED,
|
|
@@ -26,22 +28,16 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
|
26
28
|
WorkerRegisterResponse,
|
|
27
29
|
)
|
|
28
30
|
from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
|
|
29
|
-
|
|
30
|
-
from ...loader import ClientConfig
|
|
31
|
-
from ...metadata import get_metadata
|
|
31
|
+
from hatchet_sdk.metadata import get_metadata
|
|
32
32
|
|
|
33
33
|
DEFAULT_REGISTER_TIMEOUT = 30
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def new_dispatcher(config: ClientConfig) -> "DispatcherClient":
|
|
37
|
-
return DispatcherClient(config=config)
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
class DispatcherClient:
|
|
41
37
|
config: ClientConfig
|
|
42
38
|
|
|
43
39
|
def __init__(self, config: ClientConfig):
|
|
44
|
-
conn = new_conn(config)
|
|
40
|
+
conn = new_conn(config, False)
|
|
45
41
|
self.client = DispatcherStub(conn) # type: ignore[no-untyped-call]
|
|
46
42
|
|
|
47
43
|
aio_conn = new_conn(config, True)
|
|
@@ -76,7 +72,7 @@ class DispatcherClient:
|
|
|
76
72
|
|
|
77
73
|
async def send_step_action_event(
|
|
78
74
|
self, action: Action, event_type: StepActionEventType, payload: str
|
|
79
|
-
) ->
|
|
75
|
+
) -> grpc.aio.UnaryUnaryCall[StepActionEvent, ActionEventResponse] | None:
|
|
80
76
|
try:
|
|
81
77
|
return await self._try_send_step_action_event(action, event_type, payload)
|
|
82
78
|
except Exception as e:
|
|
@@ -91,12 +87,12 @@ class DispatcherClient:
|
|
|
91
87
|
"Failed to send finished event: " + str(e),
|
|
92
88
|
)
|
|
93
89
|
|
|
94
|
-
return
|
|
90
|
+
return None
|
|
95
91
|
|
|
96
92
|
@tenacity_retry
|
|
97
93
|
async def _try_send_step_action_event(
|
|
98
94
|
self, action: Action, event_type: StepActionEventType, payload: str
|
|
99
|
-
) ->
|
|
95
|
+
) -> grpc.aio.UnaryUnaryCall[StepActionEvent, ActionEventResponse]:
|
|
100
96
|
eventTimestamp = Timestamp()
|
|
101
97
|
eventTimestamp.GetCurrentTime()
|
|
102
98
|
|
|
@@ -113,15 +109,17 @@ class DispatcherClient:
|
|
|
113
109
|
retryCount=action.retry_count,
|
|
114
110
|
)
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
112
|
+
return cast(
|
|
113
|
+
grpc.aio.UnaryUnaryCall[StepActionEvent, ActionEventResponse],
|
|
114
|
+
await self.aio_client.SendStepActionEvent(
|
|
115
|
+
event,
|
|
116
|
+
metadata=get_metadata(self.token),
|
|
117
|
+
),
|
|
120
118
|
)
|
|
121
119
|
|
|
122
120
|
async def send_group_key_action_event(
|
|
123
121
|
self, action: Action, event_type: GroupKeyActionEventType, payload: str
|
|
124
|
-
) ->
|
|
122
|
+
) -> grpc.aio.UnaryUnaryCall[GroupKeyActionEvent, ActionEventResponse]:
|
|
125
123
|
eventTimestamp = Timestamp()
|
|
126
124
|
eventTimestamp.GetCurrentTime()
|
|
127
125
|
|
|
@@ -135,10 +133,12 @@ class DispatcherClient:
|
|
|
135
133
|
eventPayload=payload,
|
|
136
134
|
)
|
|
137
135
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
return cast(
|
|
137
|
+
grpc.aio.UnaryUnaryCall[GroupKeyActionEvent, ActionEventResponse],
|
|
138
|
+
await self.aio_client.SendGroupKeyActionEvent(
|
|
139
|
+
event,
|
|
140
|
+
metadata=get_metadata(self.token),
|
|
141
|
+
),
|
|
142
142
|
)
|
|
143
143
|
|
|
144
144
|
def put_overrides_data(self, data: OverridesData) -> ActionEventResponse:
|
hatchet_sdk/clients/event_ts.py
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import TypeVar, cast
|
|
3
3
|
|
|
4
|
+
import grpc.aio
|
|
5
|
+
from grpc._cython import cygrpc # type: ignore[attr-defined]
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
class ThreadSafeEvent(asyncio.Event):
|
|
6
9
|
"""
|
|
7
|
-
|
|
10
|
+
ThreadSafeEvent is a subclass of asyncio.Event that allows for thread-safe setting and clearing of the event.
|
|
8
11
|
"""
|
|
9
12
|
|
|
10
|
-
def __init__(self
|
|
11
|
-
super().__init__(
|
|
12
|
-
if self._loop is None:
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
super().__init__()
|
|
15
|
+
if self._loop is None: # type: ignore[has-type]
|
|
13
16
|
self._loop = asyncio.get_event_loop()
|
|
14
17
|
|
|
15
|
-
def set(self):
|
|
18
|
+
def set(self) -> None:
|
|
16
19
|
if not self._loop.is_closed():
|
|
17
20
|
self._loop.call_soon_threadsafe(super().set)
|
|
18
21
|
|
|
19
|
-
def clear(self):
|
|
22
|
+
def clear(self) -> None:
|
|
20
23
|
self._loop.call_soon_threadsafe(super().clear)
|
|
21
24
|
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
TRequest = TypeVar("TRequest")
|
|
27
|
+
TResponse = TypeVar("TResponse")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
async def read_with_interrupt(
|
|
31
|
+
listener: grpc.aio.UnaryStreamCall[TRequest, TResponse], interrupt: ThreadSafeEvent
|
|
32
|
+
) -> TResponse:
|
|
24
33
|
try:
|
|
25
34
|
result = await listener.read()
|
|
26
|
-
|
|
35
|
+
|
|
36
|
+
if result is cygrpc.EOF:
|
|
37
|
+
raise ValueError("Unexpected EOF")
|
|
38
|
+
|
|
39
|
+
return cast(TResponse, result)
|
|
27
40
|
finally:
|
|
28
41
|
interrupt.set()
|