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
hatchet_sdk/worker/__init__.py
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .worker import Worker, WorkerStartOptions, WorkerStatus
|
|
@@ -4,22 +4,22 @@ import signal
|
|
|
4
4
|
import time
|
|
5
5
|
from dataclasses import dataclass, field
|
|
6
6
|
from multiprocessing import Queue
|
|
7
|
-
from typing import Any, List,
|
|
7
|
+
from typing import Any, List, Literal
|
|
8
8
|
|
|
9
9
|
import grpc
|
|
10
10
|
|
|
11
|
-
from hatchet_sdk.clients.dispatcher.action_listener import
|
|
12
|
-
|
|
11
|
+
from hatchet_sdk.clients.dispatcher.action_listener import (
|
|
12
|
+
Action,
|
|
13
13
|
ActionListener,
|
|
14
|
+
ActionType,
|
|
14
15
|
GetActionListenerRequest,
|
|
15
|
-
new_dispatcher,
|
|
16
16
|
)
|
|
17
|
+
from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
|
|
18
|
+
from hatchet_sdk.config import ClientConfig
|
|
17
19
|
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
18
20
|
GROUP_KEY_EVENT_TYPE_STARTED,
|
|
19
21
|
STEP_EVENT_TYPE_STARTED,
|
|
20
|
-
ActionType,
|
|
21
22
|
)
|
|
22
|
-
from hatchet_sdk.loader import ClientConfig
|
|
23
23
|
from hatchet_sdk.logger import logger
|
|
24
24
|
from hatchet_sdk.utils.backoff import exp_backoff_sleep
|
|
25
25
|
|
|
@@ -30,10 +30,11 @@ ACTION_EVENT_RETRY_COUNT = 5
|
|
|
30
30
|
class ActionEvent:
|
|
31
31
|
action: Action
|
|
32
32
|
type: Any # TODO type
|
|
33
|
-
payload:
|
|
33
|
+
payload: str
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
STOP_LOOP_TYPE = Literal["STOP_LOOP"]
|
|
37
|
+
STOP_LOOP: STOP_LOOP_TYPE = "STOP_LOOP" # Sentinel object to stop the loop
|
|
37
38
|
|
|
38
39
|
# TODO link to a block post
|
|
39
40
|
BLOCKED_THREAD_WARNING = (
|
|
@@ -41,7 +42,7 @@ BLOCKED_THREAD_WARNING = (
|
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
|
|
44
|
-
def noop_handler():
|
|
45
|
+
def noop_handler() -> None:
|
|
45
46
|
pass
|
|
46
47
|
|
|
47
48
|
|
|
@@ -51,22 +52,22 @@ class WorkerActionListenerProcess:
|
|
|
51
52
|
actions: List[str]
|
|
52
53
|
max_runs: int
|
|
53
54
|
config: ClientConfig
|
|
54
|
-
action_queue: Queue
|
|
55
|
-
event_queue: Queue
|
|
55
|
+
action_queue: "Queue[Action]"
|
|
56
|
+
event_queue: "Queue[ActionEvent | STOP_LOOP_TYPE]"
|
|
56
57
|
handle_kill: bool = True
|
|
57
58
|
debug: bool = False
|
|
58
|
-
labels: dict = field(default_factory=dict)
|
|
59
|
+
labels: dict[str, str | int] = field(default_factory=dict)
|
|
59
60
|
|
|
60
|
-
listener: ActionListener = field(init=False
|
|
61
|
+
listener: ActionListener = field(init=False)
|
|
61
62
|
|
|
62
63
|
killing: bool = field(init=False, default=False)
|
|
63
64
|
|
|
64
|
-
action_loop_task: asyncio.Task = field(init=False, default=None)
|
|
65
|
-
event_send_loop_task: asyncio.Task = field(init=False, default=None)
|
|
65
|
+
action_loop_task: asyncio.Task[None] | None = field(init=False, default=None)
|
|
66
|
+
event_send_loop_task: asyncio.Task[None] | None = field(init=False, default=None)
|
|
66
67
|
|
|
67
|
-
running_step_runs:
|
|
68
|
+
running_step_runs: dict[str, float] = field(init=False, default_factory=dict)
|
|
68
69
|
|
|
69
|
-
def __post_init__(self):
|
|
70
|
+
def __post_init__(self) -> None:
|
|
70
71
|
if self.debug:
|
|
71
72
|
logger.setLevel(logging.DEBUG)
|
|
72
73
|
|
|
@@ -77,7 +78,7 @@ class WorkerActionListenerProcess:
|
|
|
77
78
|
signal.SIGQUIT, lambda: asyncio.create_task(self.exit_gracefully())
|
|
78
79
|
)
|
|
79
80
|
|
|
80
|
-
async def start(self, retry_attempt=0):
|
|
81
|
+
async def start(self, retry_attempt: int = 0) -> None:
|
|
81
82
|
if retry_attempt > 5:
|
|
82
83
|
logger.error("could not start action listener")
|
|
83
84
|
return
|
|
@@ -85,7 +86,7 @@ class WorkerActionListenerProcess:
|
|
|
85
86
|
logger.debug(f"starting action listener: {self.name}")
|
|
86
87
|
|
|
87
88
|
try:
|
|
88
|
-
self.dispatcher_client =
|
|
89
|
+
self.dispatcher_client = DispatcherClient(self.config)
|
|
89
90
|
|
|
90
91
|
self.listener = await self.dispatcher_client.get_action_listener(
|
|
91
92
|
GetActionListenerRequest(
|
|
@@ -108,13 +109,13 @@ class WorkerActionListenerProcess:
|
|
|
108
109
|
self.blocked_main_loop = asyncio.create_task(self.start_blocked_main_loop())
|
|
109
110
|
|
|
110
111
|
# TODO move event methods to separate class
|
|
111
|
-
async def _get_event(self):
|
|
112
|
+
async def _get_event(self) -> ActionEvent | STOP_LOOP_TYPE:
|
|
112
113
|
loop = asyncio.get_running_loop()
|
|
113
114
|
return await loop.run_in_executor(None, self.event_queue.get)
|
|
114
115
|
|
|
115
|
-
async def start_event_send_loop(self):
|
|
116
|
+
async def start_event_send_loop(self) -> None:
|
|
116
117
|
while True:
|
|
117
|
-
event
|
|
118
|
+
event = await self._get_event()
|
|
118
119
|
if event == STOP_LOOP:
|
|
119
120
|
logger.debug("stopping event send loop...")
|
|
120
121
|
break
|
|
@@ -122,11 +123,11 @@ class WorkerActionListenerProcess:
|
|
|
122
123
|
logger.debug(f"tx: event: {event.action.action_id}/{event.type}")
|
|
123
124
|
asyncio.create_task(self.send_event(event))
|
|
124
125
|
|
|
125
|
-
async def start_blocked_main_loop(self):
|
|
126
|
+
async def start_blocked_main_loop(self) -> None:
|
|
126
127
|
threshold = 1
|
|
127
128
|
while not self.killing:
|
|
128
129
|
count = 0
|
|
129
|
-
for
|
|
130
|
+
for _, start_time in self.running_step_runs.items():
|
|
130
131
|
diff = self.now() - start_time
|
|
131
132
|
if diff > threshold:
|
|
132
133
|
count += 1
|
|
@@ -135,7 +136,7 @@ class WorkerActionListenerProcess:
|
|
|
135
136
|
logger.warning(f"{BLOCKED_THREAD_WARNING}: Waiting Steps {count}")
|
|
136
137
|
await asyncio.sleep(1)
|
|
137
138
|
|
|
138
|
-
async def send_event(self, event: ActionEvent, retry_attempt: int = 1):
|
|
139
|
+
async def send_event(self, event: ActionEvent, retry_attempt: int = 1) -> None:
|
|
139
140
|
try:
|
|
140
141
|
match event.action.action_type:
|
|
141
142
|
# FIXME: all events sent from an execution of a function are of type ActionType.START_STEP_RUN since
|
|
@@ -185,10 +186,10 @@ class WorkerActionListenerProcess:
|
|
|
185
186
|
await exp_backoff_sleep(retry_attempt, 1)
|
|
186
187
|
await self.send_event(event, retry_attempt + 1)
|
|
187
188
|
|
|
188
|
-
def now(self):
|
|
189
|
+
def now(self) -> float:
|
|
189
190
|
return time.time()
|
|
190
191
|
|
|
191
|
-
async def start_action_loop(self):
|
|
192
|
+
async def start_action_loop(self) -> None:
|
|
192
193
|
try:
|
|
193
194
|
async for action in self.listener:
|
|
194
195
|
if action is None:
|
|
@@ -201,6 +202,7 @@ class WorkerActionListenerProcess:
|
|
|
201
202
|
ActionEvent(
|
|
202
203
|
action=action,
|
|
203
204
|
type=STEP_EVENT_TYPE_STARTED, # TODO ack type
|
|
205
|
+
payload="",
|
|
204
206
|
)
|
|
205
207
|
)
|
|
206
208
|
logger.info(
|
|
@@ -220,6 +222,7 @@ class WorkerActionListenerProcess:
|
|
|
220
222
|
ActionEvent(
|
|
221
223
|
action=action,
|
|
222
224
|
type=GROUP_KEY_EVENT_TYPE_STARTED, # TODO ack type
|
|
225
|
+
payload="",
|
|
223
226
|
)
|
|
224
227
|
)
|
|
225
228
|
logger.info(
|
|
@@ -239,9 +242,9 @@ class WorkerActionListenerProcess:
|
|
|
239
242
|
finally:
|
|
240
243
|
logger.info("action loop closed")
|
|
241
244
|
if not self.killing:
|
|
242
|
-
await self.exit_gracefully(
|
|
245
|
+
await self.exit_gracefully()
|
|
243
246
|
|
|
244
|
-
async def cleanup(self):
|
|
247
|
+
async def cleanup(self) -> None:
|
|
245
248
|
self.killing = True
|
|
246
249
|
|
|
247
250
|
if self.listener is not None:
|
|
@@ -249,7 +252,7 @@ class WorkerActionListenerProcess:
|
|
|
249
252
|
|
|
250
253
|
self.event_queue.put(STOP_LOOP)
|
|
251
254
|
|
|
252
|
-
async def exit_gracefully(self
|
|
255
|
+
async def exit_gracefully(self) -> None:
|
|
253
256
|
if self.killing:
|
|
254
257
|
return
|
|
255
258
|
|
|
@@ -262,13 +265,13 @@ class WorkerActionListenerProcess:
|
|
|
262
265
|
|
|
263
266
|
logger.info("action listener closed")
|
|
264
267
|
|
|
265
|
-
def exit_forcefully(self):
|
|
268
|
+
def exit_forcefully(self) -> None:
|
|
266
269
|
asyncio.run(self.cleanup())
|
|
267
270
|
logger.debug("forcefully closing listener...")
|
|
268
271
|
|
|
269
272
|
|
|
270
|
-
def worker_action_listener_process(*args, **kwargs):
|
|
271
|
-
async def run():
|
|
273
|
+
def worker_action_listener_process(*args: Any, **kwargs: Any) -> None:
|
|
274
|
+
async def run() -> None:
|
|
272
275
|
process = WorkerActionListenerProcess(*args, **kwargs)
|
|
273
276
|
await process.start()
|
|
274
277
|
# Keep the process running
|
|
@@ -2,18 +2,20 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from multiprocessing import Queue
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Literal, TypeVar
|
|
6
6
|
|
|
7
|
-
from hatchet_sdk import Context
|
|
8
7
|
from hatchet_sdk.client import Client, new_client_raw
|
|
9
8
|
from hatchet_sdk.clients.dispatcher.action_listener import Action
|
|
10
|
-
from hatchet_sdk.
|
|
9
|
+
from hatchet_sdk.config import ClientConfig
|
|
11
10
|
from hatchet_sdk.logger import logger
|
|
12
|
-
from hatchet_sdk.utils.
|
|
11
|
+
from hatchet_sdk.utils.typing import WorkflowValidator
|
|
12
|
+
from hatchet_sdk.worker.action_listener_process import ActionEvent
|
|
13
13
|
from hatchet_sdk.worker.runner.runner import Runner
|
|
14
14
|
from hatchet_sdk.worker.runner.utils.capture_logs import capture_logs
|
|
15
|
+
from hatchet_sdk.workflow import Step
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
STOP_LOOP_TYPE = Literal["STOP_LOOP"]
|
|
18
|
+
STOP_LOOP: STOP_LOOP_TYPE = "STOP_LOOP"
|
|
17
19
|
|
|
18
20
|
T = TypeVar("T")
|
|
19
21
|
|
|
@@ -21,32 +23,32 @@ T = TypeVar("T")
|
|
|
21
23
|
@dataclass
|
|
22
24
|
class WorkerActionRunLoopManager:
|
|
23
25
|
name: str
|
|
24
|
-
action_registry: dict[str,
|
|
26
|
+
action_registry: dict[str, Step[Any]]
|
|
25
27
|
validator_registry: dict[str, WorkflowValidator]
|
|
26
28
|
max_runs: int | None
|
|
27
29
|
config: ClientConfig
|
|
28
|
-
action_queue: Queue
|
|
29
|
-
event_queue: Queue
|
|
30
|
+
action_queue: "Queue[Action | STOP_LOOP_TYPE]"
|
|
31
|
+
event_queue: "Queue[ActionEvent]"
|
|
30
32
|
loop: asyncio.AbstractEventLoop
|
|
31
33
|
handle_kill: bool = True
|
|
32
34
|
debug: bool = False
|
|
33
35
|
labels: dict[str, str | int] = field(default_factory=dict)
|
|
34
36
|
|
|
35
|
-
client: Client = field(init=False
|
|
37
|
+
client: Client = field(init=False)
|
|
36
38
|
|
|
37
39
|
killing: bool = field(init=False, default=False)
|
|
38
|
-
runner: Runner = field(init=False, default=None)
|
|
40
|
+
runner: Runner | None = field(init=False, default=None)
|
|
39
41
|
|
|
40
|
-
def __post_init__(self):
|
|
42
|
+
def __post_init__(self) -> None:
|
|
41
43
|
if self.debug:
|
|
42
44
|
logger.setLevel(logging.DEBUG)
|
|
43
45
|
self.client = new_client_raw(self.config, self.debug)
|
|
44
46
|
self.start()
|
|
45
47
|
|
|
46
|
-
def start(self, retry_count=1):
|
|
47
|
-
k = self.loop.create_task(self.
|
|
48
|
+
def start(self, retry_count: int = 1) -> None:
|
|
49
|
+
k = self.loop.create_task(self.aio_start(retry_count)) # noqa: F841
|
|
48
50
|
|
|
49
|
-
async def
|
|
51
|
+
async def aio_start(self, retry_count: int = 1) -> None:
|
|
50
52
|
await capture_logs(
|
|
51
53
|
self.client.logInterceptor,
|
|
52
54
|
self.client.event,
|
|
@@ -83,7 +85,7 @@ class WorkerActionRunLoopManager:
|
|
|
83
85
|
|
|
84
86
|
logger.debug(f"'{self.name}' waiting for {list(self.action_registry.keys())}")
|
|
85
87
|
while not self.killing:
|
|
86
|
-
action
|
|
88
|
+
action = await self._get_action()
|
|
87
89
|
if action == STOP_LOOP:
|
|
88
90
|
logger.debug("stopping action runner loop...")
|
|
89
91
|
break
|
|
@@ -91,7 +93,7 @@ class WorkerActionRunLoopManager:
|
|
|
91
93
|
self.runner.run(action)
|
|
92
94
|
logger.debug("action runner loop stopped")
|
|
93
95
|
|
|
94
|
-
async def _get_action(self):
|
|
96
|
+
async def _get_action(self) -> Action | STOP_LOOP_TYPE:
|
|
95
97
|
return await self.loop.run_in_executor(None, self.action_queue.get)
|
|
96
98
|
|
|
97
99
|
async def exit_gracefully(self) -> None:
|
|
@@ -8,17 +8,18 @@ from concurrent.futures import ThreadPoolExecutor
|
|
|
8
8
|
from enum import Enum
|
|
9
9
|
from multiprocessing import Queue
|
|
10
10
|
from threading import Thread, current_thread
|
|
11
|
-
from typing import Any, Callable, Dict,
|
|
11
|
+
from typing import Any, Callable, Dict, TypeVar, cast
|
|
12
12
|
|
|
13
13
|
from pydantic import BaseModel
|
|
14
14
|
|
|
15
15
|
from hatchet_sdk.client import new_client_raw
|
|
16
|
-
from hatchet_sdk.clients.admin import
|
|
17
|
-
from hatchet_sdk.clients.dispatcher.action_listener import Action
|
|
18
|
-
from hatchet_sdk.clients.dispatcher.dispatcher import
|
|
19
|
-
from hatchet_sdk.clients.run_event_listener import
|
|
16
|
+
from hatchet_sdk.clients.admin import AdminClient
|
|
17
|
+
from hatchet_sdk.clients.dispatcher.action_listener import Action, ActionType
|
|
18
|
+
from hatchet_sdk.clients.dispatcher.dispatcher import DispatcherClient
|
|
19
|
+
from hatchet_sdk.clients.run_event_listener import RunEventListenerClient
|
|
20
20
|
from hatchet_sdk.clients.workflow_listener import PooledWorkflowRunListener
|
|
21
|
-
from hatchet_sdk.
|
|
21
|
+
from hatchet_sdk.config import ClientConfig
|
|
22
|
+
from hatchet_sdk.context.context import Context
|
|
22
23
|
from hatchet_sdk.context.worker_context import WorkerContext
|
|
23
24
|
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
24
25
|
GROUP_KEY_EVENT_TYPE_COMPLETED,
|
|
@@ -27,14 +28,14 @@ from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
|
27
28
|
STEP_EVENT_TYPE_COMPLETED,
|
|
28
29
|
STEP_EVENT_TYPE_FAILED,
|
|
29
30
|
STEP_EVENT_TYPE_STARTED,
|
|
30
|
-
ActionType,
|
|
31
31
|
)
|
|
32
|
-
from hatchet_sdk.loader import ClientConfig
|
|
33
32
|
from hatchet_sdk.logger import logger
|
|
34
|
-
from hatchet_sdk.utils.
|
|
35
|
-
from hatchet_sdk.v2.callable import DurableContext
|
|
33
|
+
from hatchet_sdk.utils.typing import WorkflowValidator
|
|
36
34
|
from hatchet_sdk.worker.action_listener_process import ActionEvent
|
|
37
35
|
from hatchet_sdk.worker.runner.utils.capture_logs import copy_context_vars, sr, wr
|
|
36
|
+
from hatchet_sdk.workflow import Step
|
|
37
|
+
|
|
38
|
+
T = TypeVar("T")
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class WorkerStatus(Enum):
|
|
@@ -51,7 +52,7 @@ class Runner:
|
|
|
51
52
|
event_queue: "Queue[Any]",
|
|
52
53
|
max_runs: int | None = None,
|
|
53
54
|
handle_kill: bool = True,
|
|
54
|
-
action_registry: dict[str,
|
|
55
|
+
action_registry: dict[str, Step[T]] = {},
|
|
55
56
|
validator_registry: dict[str, WorkflowValidator] = {},
|
|
56
57
|
config: ClientConfig = ClientConfig(),
|
|
57
58
|
labels: dict[str, str | int] = {},
|
|
@@ -63,7 +64,7 @@ class Runner:
|
|
|
63
64
|
self.max_runs = max_runs
|
|
64
65
|
self.tasks: dict[str, asyncio.Task[Any]] = {} # Store run ids and futures
|
|
65
66
|
self.contexts: dict[str, Context] = {} # Store run ids and contexts
|
|
66
|
-
self.action_registry: dict[str,
|
|
67
|
+
self.action_registry: dict[str, Step[T]] = action_registry
|
|
67
68
|
self.validator_registry = validator_registry
|
|
68
69
|
|
|
69
70
|
self.event_queue = event_queue
|
|
@@ -77,9 +78,9 @@ class Runner:
|
|
|
77
78
|
|
|
78
79
|
# We need to initialize a new admin and dispatcher client *after* we've started the event loop,
|
|
79
80
|
# otherwise the grpc.aio methods will use a different event loop and we'll get a bunch of errors.
|
|
80
|
-
self.dispatcher_client =
|
|
81
|
-
self.admin_client =
|
|
82
|
-
self.workflow_run_event_listener =
|
|
81
|
+
self.dispatcher_client = DispatcherClient(self.config)
|
|
82
|
+
self.admin_client = AdminClient(self.config)
|
|
83
|
+
self.workflow_run_event_listener = RunEventListenerClient(self.config)
|
|
83
84
|
self.client.workflow_listener = PooledWorkflowRunListener(self.config)
|
|
84
85
|
|
|
85
86
|
self.worker_context = WorkerContext(
|
|
@@ -194,10 +195,7 @@ class Runner:
|
|
|
194
195
|
|
|
195
196
|
return inner_callback
|
|
196
197
|
|
|
197
|
-
|
|
198
|
-
def thread_action_func(
|
|
199
|
-
self, context: Context, action_func: Callable[..., Any], action: Action
|
|
200
|
-
) -> Any:
|
|
198
|
+
def thread_action_func(self, context: Context, step: Step[T], action: Action) -> T:
|
|
201
199
|
if action.step_run_id is not None and action.step_run_id != "":
|
|
202
200
|
self.threads[action.step_run_id] = current_thread()
|
|
203
201
|
elif (
|
|
@@ -206,25 +204,22 @@ class Runner:
|
|
|
206
204
|
):
|
|
207
205
|
self.threads[action.get_group_key_run_id] = current_thread()
|
|
208
206
|
|
|
209
|
-
return
|
|
207
|
+
return step.call(context)
|
|
210
208
|
|
|
211
|
-
## TODO: Stricter type hinting here
|
|
212
209
|
# We wrap all actions in an async func
|
|
213
210
|
async def async_wrapped_action_func(
|
|
214
211
|
self,
|
|
215
212
|
context: Context,
|
|
216
|
-
|
|
213
|
+
step: Step[T],
|
|
217
214
|
action: Action,
|
|
218
215
|
run_id: str,
|
|
219
|
-
) ->
|
|
220
|
-
wr.set(context.workflow_run_id
|
|
216
|
+
) -> T:
|
|
217
|
+
wr.set(context.workflow_run_id)
|
|
221
218
|
sr.set(context.step_run_id)
|
|
222
219
|
|
|
223
220
|
try:
|
|
224
|
-
if
|
|
225
|
-
|
|
226
|
-
) or asyncio.iscoroutinefunction(action_func):
|
|
227
|
-
return await action_func(context)
|
|
221
|
+
if step.is_async_function:
|
|
222
|
+
return await step.aio_call(context)
|
|
228
223
|
else:
|
|
229
224
|
pfunc = functools.partial(
|
|
230
225
|
# we must copy the context vars to the new thread, as only asyncio natively supports
|
|
@@ -233,7 +228,7 @@ class Runner:
|
|
|
233
228
|
contextvars.copy_context().items(),
|
|
234
229
|
self.thread_action_func,
|
|
235
230
|
context,
|
|
236
|
-
|
|
231
|
+
step,
|
|
237
232
|
action,
|
|
238
233
|
)
|
|
239
234
|
|
|
@@ -260,23 +255,7 @@ class Runner:
|
|
|
260
255
|
if run_id in self.contexts:
|
|
261
256
|
del self.contexts[run_id]
|
|
262
257
|
|
|
263
|
-
def create_context(
|
|
264
|
-
self, action: Action, action_func: Callable[..., Any] | None
|
|
265
|
-
) -> Context | DurableContext:
|
|
266
|
-
if hasattr(action_func, "durable") and getattr(action_func, "durable"):
|
|
267
|
-
return DurableContext(
|
|
268
|
-
action,
|
|
269
|
-
self.dispatcher_client,
|
|
270
|
-
self.admin_client,
|
|
271
|
-
self.client.event,
|
|
272
|
-
self.client.rest,
|
|
273
|
-
self.client.workflow_listener,
|
|
274
|
-
self.workflow_run_event_listener,
|
|
275
|
-
self.worker_context,
|
|
276
|
-
self.client.config.namespace,
|
|
277
|
-
validator_registry=self.validator_registry,
|
|
278
|
-
)
|
|
279
|
-
|
|
258
|
+
def create_context(self, action: Action) -> Context:
|
|
280
259
|
return Context(
|
|
281
260
|
action,
|
|
282
261
|
self.dispatcher_client,
|
|
@@ -291,22 +270,19 @@ class Runner:
|
|
|
291
270
|
)
|
|
292
271
|
|
|
293
272
|
## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
|
|
294
|
-
async def handle_start_step_run(self, action: Action) -> None
|
|
273
|
+
async def handle_start_step_run(self, action: Action) -> None:
|
|
295
274
|
action_name = action.action_id
|
|
296
275
|
|
|
297
276
|
# Find the corresponding action function from the registry
|
|
298
277
|
action_func = self.action_registry.get(action_name)
|
|
299
278
|
|
|
300
|
-
context = self.create_context(action
|
|
279
|
+
context = self.create_context(action)
|
|
301
280
|
|
|
302
281
|
self.contexts[action.step_run_id] = context
|
|
303
282
|
|
|
304
283
|
if action_func:
|
|
305
284
|
self.event_queue.put(
|
|
306
|
-
ActionEvent(
|
|
307
|
-
action=action,
|
|
308
|
-
type=STEP_EVENT_TYPE_STARTED,
|
|
309
|
-
)
|
|
285
|
+
ActionEvent(action=action, type=STEP_EVENT_TYPE_STARTED, payload="")
|
|
310
286
|
)
|
|
311
287
|
|
|
312
288
|
loop = asyncio.get_event_loop()
|
|
@@ -321,10 +297,9 @@ class Runner:
|
|
|
321
297
|
|
|
322
298
|
try:
|
|
323
299
|
await task
|
|
324
|
-
except Exception
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return None
|
|
300
|
+
except Exception:
|
|
301
|
+
# do nothing, this should be caught in the callback
|
|
302
|
+
pass
|
|
328
303
|
|
|
329
304
|
## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
|
|
330
305
|
async def handle_start_group_key_run(self, action: Action) -> Exception | None:
|
|
@@ -350,8 +325,7 @@ class Runner:
|
|
|
350
325
|
# send an event that the group key run has started
|
|
351
326
|
self.event_queue.put(
|
|
352
327
|
ActionEvent(
|
|
353
|
-
action=action,
|
|
354
|
-
type=GROUP_KEY_EVENT_TYPE_STARTED,
|
|
328
|
+
action=action, type=GROUP_KEY_EVENT_TYPE_STARTED, payload=""
|
|
355
329
|
)
|
|
356
330
|
)
|
|
357
331
|
|
|
@@ -421,6 +395,11 @@ class Runner:
|
|
|
421
395
|
|
|
422
396
|
# check if thread is still running, if so, print a warning
|
|
423
397
|
if run_id in self.threads:
|
|
398
|
+
thread = self.threads.get(run_id)
|
|
399
|
+
if thread and self.client.config.enable_force_kill_sync_threads:
|
|
400
|
+
self.force_kill_thread(thread)
|
|
401
|
+
await asyncio.sleep(1)
|
|
402
|
+
|
|
424
403
|
logger.warning(
|
|
425
404
|
f"Thread {self.threads[run_id].ident} with run id {run_id} is still running after cancellation. This could cause the thread pool to get blocked and prevent new tasks from running."
|
|
426
405
|
)
|
|
@@ -428,7 +407,6 @@ class Runner:
|
|
|
428
407
|
self.cleanup_run_id(run_id)
|
|
429
408
|
|
|
430
409
|
def serialize_output(self, output: Any) -> str:
|
|
431
|
-
|
|
432
410
|
if isinstance(output, BaseModel):
|
|
433
411
|
return output.model_dump_json()
|
|
434
412
|
|
|
@@ -2,11 +2,12 @@ import contextvars
|
|
|
2
2
|
import functools
|
|
3
3
|
import logging
|
|
4
4
|
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
from contextvars import ContextVar
|
|
5
6
|
from io import StringIO
|
|
6
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Awaitable, Callable, ItemsView, ParamSpec, TypeVar
|
|
7
8
|
|
|
8
|
-
from hatchet_sdk import logger
|
|
9
9
|
from hatchet_sdk.clients.events import EventClient
|
|
10
|
+
from hatchet_sdk.logger import logger
|
|
10
11
|
|
|
11
12
|
wr: contextvars.ContextVar[str | None] = contextvars.ContextVar(
|
|
12
13
|
"workflow_run_id", default=None
|
|
@@ -16,7 +17,16 @@ sr: contextvars.ContextVar[str | None] = contextvars.ContextVar(
|
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
T = TypeVar("T")
|
|
21
|
+
P = ParamSpec("P")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def copy_context_vars(
|
|
25
|
+
ctx_vars: ItemsView[ContextVar[Any], Any],
|
|
26
|
+
func: Callable[P, T],
|
|
27
|
+
*args: P.args,
|
|
28
|
+
**kwargs: P.kwargs,
|
|
29
|
+
) -> T:
|
|
20
30
|
for var, value in ctx_vars:
|
|
21
31
|
var.set(value)
|
|
22
32
|
return func(*args, **kwargs)
|
|
@@ -25,19 +35,20 @@ def copy_context_vars(ctx_vars, func, *args, **kwargs):
|
|
|
25
35
|
class InjectingFilter(logging.Filter):
|
|
26
36
|
# For some reason, only the InjectingFilter has access to the contextvars method sr.get(),
|
|
27
37
|
# otherwise we would use emit within the CustomLogHandler
|
|
28
|
-
def filter(self, record):
|
|
38
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
39
|
+
## TODO: Change how we do this to not assign to the log record
|
|
29
40
|
record.workflow_run_id = wr.get()
|
|
30
41
|
record.step_run_id = sr.get()
|
|
31
42
|
return True
|
|
32
43
|
|
|
33
44
|
|
|
34
|
-
class CustomLogHandler(logging.StreamHandler):
|
|
35
|
-
def __init__(self, event_client: EventClient, stream=None):
|
|
45
|
+
class CustomLogHandler(logging.StreamHandler): # type: ignore[type-arg]
|
|
46
|
+
def __init__(self, event_client: EventClient, stream: StringIO | None = None):
|
|
36
47
|
super().__init__(stream)
|
|
37
48
|
self.logger_thread_pool = ThreadPoolExecutor(max_workers=1)
|
|
38
49
|
self.event_client = event_client
|
|
39
50
|
|
|
40
|
-
def _log(self, line: str, step_run_id: str | None):
|
|
51
|
+
def _log(self, line: str, step_run_id: str | None) -> None:
|
|
41
52
|
try:
|
|
42
53
|
if not step_run_id:
|
|
43
54
|
return
|
|
@@ -46,20 +57,20 @@ class CustomLogHandler(logging.StreamHandler):
|
|
|
46
57
|
except Exception as e:
|
|
47
58
|
logger.error(f"Error logging: {e}")
|
|
48
59
|
|
|
49
|
-
def emit(self, record):
|
|
60
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
50
61
|
super().emit(record)
|
|
51
62
|
|
|
52
63
|
log_entry = self.format(record)
|
|
53
|
-
|
|
64
|
+
|
|
65
|
+
## TODO: Change how we do this to not assign to the log record
|
|
66
|
+
self.logger_thread_pool.submit(self._log, log_entry, record.step_run_id) # type: ignore
|
|
54
67
|
|
|
55
68
|
|
|
56
69
|
def capture_logs(
|
|
57
|
-
logger: logging.Logger,
|
|
58
|
-
|
|
59
|
-
func: Coroutine[Any, Any, Any],
|
|
60
|
-
):
|
|
70
|
+
logger: logging.Logger, event_client: "EventClient", func: Callable[P, Awaitable[T]]
|
|
71
|
+
) -> Callable[P, Awaitable[T]]:
|
|
61
72
|
@functools.wraps(func)
|
|
62
|
-
async def wrapper(*args, **kwargs):
|
|
73
|
+
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
|
|
63
74
|
if not logger:
|
|
64
75
|
raise Exception("No logger configured on client")
|
|
65
76
|
|