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
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
from collections.abc import AsyncIterator
|
|
4
|
+
from typing import Any, Literal, cast
|
|
5
|
+
|
|
6
|
+
import grpc
|
|
7
|
+
import grpc.aio
|
|
8
|
+
from grpc._cython import cygrpc # type: ignore[attr-defined]
|
|
9
|
+
from pydantic import BaseModel, ConfigDict
|
|
10
|
+
|
|
11
|
+
from hatchet_sdk.clients.event_ts import ThreadSafeEvent, read_with_interrupt
|
|
12
|
+
from hatchet_sdk.clients.rest.tenacity_utils import tenacity_retry
|
|
13
|
+
from hatchet_sdk.config import ClientConfig
|
|
14
|
+
from hatchet_sdk.connection import new_conn
|
|
15
|
+
from hatchet_sdk.contracts.v1.dispatcher_pb2 import (
|
|
16
|
+
DurableEvent,
|
|
17
|
+
ListenForDurableEventRequest,
|
|
18
|
+
)
|
|
19
|
+
from hatchet_sdk.contracts.v1.dispatcher_pb2 import (
|
|
20
|
+
RegisterDurableEventRequest as RegisterDurableEventRequestProto,
|
|
21
|
+
)
|
|
22
|
+
from hatchet_sdk.contracts.v1.dispatcher_pb2_grpc import V1DispatcherStub
|
|
23
|
+
from hatchet_sdk.contracts.v1.shared.condition_pb2 import DurableEventListenerConditions
|
|
24
|
+
from hatchet_sdk.logger import logger
|
|
25
|
+
from hatchet_sdk.metadata import get_metadata
|
|
26
|
+
from hatchet_sdk.waits import SleepCondition, UserEventCondition
|
|
27
|
+
|
|
28
|
+
DEFAULT_DURABLE_EVENT_LISTENER_RETRY_INTERVAL = 3 # seconds
|
|
29
|
+
DEFAULT_DURABLE_EVENT_LISTENER_RETRY_COUNT = 5
|
|
30
|
+
DEFAULT_DURABLE_EVENT_LISTENER_INTERRUPT_INTERVAL = 1800 # 30 minutes
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _Subscription:
|
|
34
|
+
def __init__(self, id: int, task_id: str, signal_key: str):
|
|
35
|
+
self.id = id
|
|
36
|
+
self.task_id = task_id
|
|
37
|
+
self.signal_key = signal_key
|
|
38
|
+
self.queue: asyncio.Queue[DurableEvent | None] = asyncio.Queue()
|
|
39
|
+
|
|
40
|
+
async def __aiter__(self) -> "_Subscription":
|
|
41
|
+
return self
|
|
42
|
+
|
|
43
|
+
async def __anext__(self) -> DurableEvent | None:
|
|
44
|
+
return await self.queue.get()
|
|
45
|
+
|
|
46
|
+
async def get(self) -> DurableEvent:
|
|
47
|
+
event = await self.queue.get()
|
|
48
|
+
|
|
49
|
+
if event is None:
|
|
50
|
+
raise StopAsyncIteration
|
|
51
|
+
|
|
52
|
+
return event
|
|
53
|
+
|
|
54
|
+
async def put(self, item: DurableEvent) -> None:
|
|
55
|
+
await self.queue.put(item)
|
|
56
|
+
|
|
57
|
+
async def close(self) -> None:
|
|
58
|
+
await self.queue.put(None)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RegisterDurableEventRequest(BaseModel):
|
|
62
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
63
|
+
|
|
64
|
+
task_id: str
|
|
65
|
+
signal_key: str
|
|
66
|
+
conditions: list[SleepCondition | UserEventCondition]
|
|
67
|
+
|
|
68
|
+
def to_proto(self) -> RegisterDurableEventRequestProto:
|
|
69
|
+
return RegisterDurableEventRequestProto(
|
|
70
|
+
task_id=self.task_id,
|
|
71
|
+
signal_key=self.signal_key,
|
|
72
|
+
conditions=DurableEventListenerConditions(
|
|
73
|
+
sleep_conditions=[
|
|
74
|
+
c.to_pb() for c in self.conditions if isinstance(c, SleepCondition)
|
|
75
|
+
],
|
|
76
|
+
user_event_conditions=[
|
|
77
|
+
c.to_pb()
|
|
78
|
+
for c in self.conditions
|
|
79
|
+
if isinstance(c, UserEventCondition)
|
|
80
|
+
],
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class DurableEventListener:
|
|
86
|
+
def __init__(self, config: ClientConfig):
|
|
87
|
+
try:
|
|
88
|
+
asyncio.get_running_loop()
|
|
89
|
+
except RuntimeError:
|
|
90
|
+
loop = asyncio.new_event_loop()
|
|
91
|
+
asyncio.set_event_loop(loop)
|
|
92
|
+
|
|
93
|
+
conn = new_conn(config, True)
|
|
94
|
+
self.client = V1DispatcherStub(conn) # type: ignore[no-untyped-call]
|
|
95
|
+
self.token = config.token
|
|
96
|
+
self.config = config
|
|
97
|
+
|
|
98
|
+
# list of all active subscriptions, mapping from a subscription id to a task id and signal key
|
|
99
|
+
self.subscriptions_to_task_id_signal_key: dict[int, tuple[str, str]] = {}
|
|
100
|
+
|
|
101
|
+
# task id-signal key tuples mapped to an array of subscription ids
|
|
102
|
+
self.task_id_signal_key_to_subscriptions: dict[tuple[str, str], list[int]] = {}
|
|
103
|
+
|
|
104
|
+
self.subscription_counter: int = 0
|
|
105
|
+
self.subscription_counter_lock: asyncio.Lock = asyncio.Lock()
|
|
106
|
+
|
|
107
|
+
self.requests: asyncio.Queue[ListenForDurableEventRequest | int] = (
|
|
108
|
+
asyncio.Queue()
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
self.listener: (
|
|
112
|
+
grpc.aio.UnaryStreamCall[ListenForDurableEventRequest, DurableEvent] | None
|
|
113
|
+
) = None
|
|
114
|
+
self.listener_task: asyncio.Task[None] | None = None
|
|
115
|
+
|
|
116
|
+
self.curr_requester: int = 0
|
|
117
|
+
|
|
118
|
+
self.events: dict[int, _Subscription] = {}
|
|
119
|
+
|
|
120
|
+
self.interrupter: asyncio.Task[None] | None = None
|
|
121
|
+
|
|
122
|
+
async def _interrupter(self) -> None:
|
|
123
|
+
"""
|
|
124
|
+
_interrupter runs in a separate thread and interrupts the listener according to a configurable duration.
|
|
125
|
+
"""
|
|
126
|
+
await asyncio.sleep(DEFAULT_DURABLE_EVENT_LISTENER_INTERRUPT_INTERVAL)
|
|
127
|
+
|
|
128
|
+
if self.interrupt is not None:
|
|
129
|
+
self.interrupt.set()
|
|
130
|
+
|
|
131
|
+
async def _init_producer(self) -> None:
|
|
132
|
+
try:
|
|
133
|
+
if not self.listener:
|
|
134
|
+
while True:
|
|
135
|
+
try:
|
|
136
|
+
self.listener = await self._retry_subscribe()
|
|
137
|
+
|
|
138
|
+
logger.debug("Workflow run listener connected.")
|
|
139
|
+
|
|
140
|
+
# spawn an interrupter task
|
|
141
|
+
if self.interrupter is not None and not self.interrupter.done():
|
|
142
|
+
self.interrupter.cancel()
|
|
143
|
+
|
|
144
|
+
self.interrupter = asyncio.create_task(self._interrupter())
|
|
145
|
+
|
|
146
|
+
while True:
|
|
147
|
+
self.interrupt = ThreadSafeEvent()
|
|
148
|
+
if self.listener is None:
|
|
149
|
+
continue
|
|
150
|
+
|
|
151
|
+
t = asyncio.create_task(
|
|
152
|
+
read_with_interrupt(self.listener, self.interrupt)
|
|
153
|
+
)
|
|
154
|
+
await self.interrupt.wait()
|
|
155
|
+
|
|
156
|
+
if not t.done():
|
|
157
|
+
logger.warning(
|
|
158
|
+
"Interrupted read_with_interrupt task of durable event listener"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
t.cancel()
|
|
162
|
+
if self.listener:
|
|
163
|
+
self.listener.cancel()
|
|
164
|
+
await asyncio.sleep(
|
|
165
|
+
DEFAULT_DURABLE_EVENT_LISTENER_RETRY_INTERVAL
|
|
166
|
+
)
|
|
167
|
+
break
|
|
168
|
+
|
|
169
|
+
event = t.result()
|
|
170
|
+
|
|
171
|
+
if event is cygrpc.EOF:
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
# get a list of subscriptions for this task-signal pair
|
|
175
|
+
subscriptions = (
|
|
176
|
+
self.task_id_signal_key_to_subscriptions.get(
|
|
177
|
+
(event.task_id, event.signal_key), []
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
for subscription_id in subscriptions:
|
|
182
|
+
await self.events[subscription_id].put(event)
|
|
183
|
+
|
|
184
|
+
except grpc.RpcError as e:
|
|
185
|
+
logger.debug(f"grpc error in durable event listener: {e}")
|
|
186
|
+
await asyncio.sleep(
|
|
187
|
+
DEFAULT_DURABLE_EVENT_LISTENER_RETRY_INTERVAL
|
|
188
|
+
)
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.error(f"Error in durable event listener: {e}")
|
|
193
|
+
|
|
194
|
+
self.listener = None
|
|
195
|
+
|
|
196
|
+
# close all subscriptions
|
|
197
|
+
for subscription_id in self.events:
|
|
198
|
+
await self.events[subscription_id].close()
|
|
199
|
+
|
|
200
|
+
raise e
|
|
201
|
+
|
|
202
|
+
async def _request(self) -> AsyncIterator[ListenForDurableEventRequest]:
|
|
203
|
+
self.curr_requester = self.curr_requester + 1
|
|
204
|
+
|
|
205
|
+
# replay all existing subscriptions
|
|
206
|
+
for task_id, signal_key in set(
|
|
207
|
+
self.subscriptions_to_task_id_signal_key.values()
|
|
208
|
+
):
|
|
209
|
+
yield ListenForDurableEventRequest(
|
|
210
|
+
task_id=task_id,
|
|
211
|
+
signal_key=signal_key,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
while True:
|
|
215
|
+
request = await self.requests.get()
|
|
216
|
+
|
|
217
|
+
# if the request is an int which matches the current requester, then we should stop
|
|
218
|
+
if request == self.curr_requester:
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
# if we've gotten an int that doesn't match the current requester, then we should ignore it
|
|
222
|
+
if isinstance(request, int):
|
|
223
|
+
continue
|
|
224
|
+
|
|
225
|
+
yield request
|
|
226
|
+
self.requests.task_done()
|
|
227
|
+
|
|
228
|
+
def cleanup_subscription(self, subscription_id: int) -> None:
|
|
229
|
+
task_id_signal_key = self.subscriptions_to_task_id_signal_key[subscription_id]
|
|
230
|
+
|
|
231
|
+
if task_id_signal_key in self.task_id_signal_key_to_subscriptions:
|
|
232
|
+
self.task_id_signal_key_to_subscriptions[task_id_signal_key].remove(
|
|
233
|
+
subscription_id
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
del self.subscriptions_to_task_id_signal_key[subscription_id]
|
|
237
|
+
del self.events[subscription_id]
|
|
238
|
+
|
|
239
|
+
async def subscribe(self, task_id: str, signal_key: str) -> DurableEvent:
|
|
240
|
+
try:
|
|
241
|
+
# create a new subscription id, place a mutex on the counter
|
|
242
|
+
async with self.subscription_counter_lock:
|
|
243
|
+
self.subscription_counter += 1
|
|
244
|
+
subscription_id = self.subscription_counter
|
|
245
|
+
|
|
246
|
+
self.subscriptions_to_task_id_signal_key[subscription_id] = (
|
|
247
|
+
task_id,
|
|
248
|
+
signal_key,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if (task_id, signal_key) not in self.task_id_signal_key_to_subscriptions:
|
|
252
|
+
self.task_id_signal_key_to_subscriptions[(task_id, signal_key)] = [
|
|
253
|
+
subscription_id
|
|
254
|
+
]
|
|
255
|
+
else:
|
|
256
|
+
self.task_id_signal_key_to_subscriptions[(task_id, signal_key)].append(
|
|
257
|
+
subscription_id
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
self.events[subscription_id] = _Subscription(
|
|
261
|
+
subscription_id, task_id, signal_key
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
await self.requests.put(
|
|
265
|
+
ListenForDurableEventRequest(
|
|
266
|
+
task_id=task_id,
|
|
267
|
+
signal_key=signal_key,
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if not self.listener_task or self.listener_task.done():
|
|
272
|
+
self.listener_task = asyncio.create_task(self._init_producer())
|
|
273
|
+
|
|
274
|
+
return await self.events[subscription_id].get()
|
|
275
|
+
except asyncio.CancelledError:
|
|
276
|
+
raise
|
|
277
|
+
finally:
|
|
278
|
+
self.cleanup_subscription(subscription_id)
|
|
279
|
+
|
|
280
|
+
async def _retry_subscribe(
|
|
281
|
+
self,
|
|
282
|
+
) -> grpc.aio.UnaryStreamCall[ListenForDurableEventRequest, DurableEvent]:
|
|
283
|
+
retries = 0
|
|
284
|
+
|
|
285
|
+
while retries < DEFAULT_DURABLE_EVENT_LISTENER_RETRY_COUNT:
|
|
286
|
+
try:
|
|
287
|
+
if retries > 0:
|
|
288
|
+
await asyncio.sleep(DEFAULT_DURABLE_EVENT_LISTENER_RETRY_INTERVAL)
|
|
289
|
+
|
|
290
|
+
# signal previous async iterator to stop
|
|
291
|
+
if self.curr_requester != 0:
|
|
292
|
+
self.requests.put_nowait(self.curr_requester)
|
|
293
|
+
|
|
294
|
+
return cast(
|
|
295
|
+
grpc.aio.UnaryStreamCall[
|
|
296
|
+
ListenForDurableEventRequest, DurableEvent
|
|
297
|
+
],
|
|
298
|
+
self.client.ListenForDurableEvent(
|
|
299
|
+
self._request(),
|
|
300
|
+
metadata=get_metadata(self.token),
|
|
301
|
+
),
|
|
302
|
+
)
|
|
303
|
+
except grpc.RpcError as e:
|
|
304
|
+
if e.code() == grpc.StatusCode.UNAVAILABLE:
|
|
305
|
+
retries = retries + 1
|
|
306
|
+
else:
|
|
307
|
+
raise ValueError(f"gRPC error: {e}")
|
|
308
|
+
|
|
309
|
+
raise ValueError("Failed to connect to durable event listener")
|
|
310
|
+
|
|
311
|
+
@tenacity_retry
|
|
312
|
+
def register_durable_event(
|
|
313
|
+
self, request: RegisterDurableEventRequest
|
|
314
|
+
) -> Literal[True]:
|
|
315
|
+
self.client.RegisterDurableEvent(
|
|
316
|
+
request.to_proto(),
|
|
317
|
+
timeout=5,
|
|
318
|
+
metadata=get_metadata(self.token),
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
return True
|
|
322
|
+
|
|
323
|
+
@tenacity_retry
|
|
324
|
+
async def result(self, task_id: str, signal_key: str) -> dict[str, Any]:
|
|
325
|
+
event = await self.subscribe(task_id, signal_key)
|
|
326
|
+
|
|
327
|
+
return cast(dict[str, Any], json.loads(event.data.decode("utf-8")))
|
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()
|
hatchet_sdk/clients/events.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import datetime
|
|
3
3
|
import json
|
|
4
|
-
from typing import
|
|
5
|
-
from uuid import uuid4
|
|
4
|
+
from typing import List, cast
|
|
6
5
|
|
|
7
6
|
import grpc
|
|
8
7
|
from google.protobuf import timestamp_pb2
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
9
|
|
|
10
10
|
from hatchet_sdk.clients.rest.tenacity_utils import tenacity_retry
|
|
11
|
+
from hatchet_sdk.config import ClientConfig
|
|
11
12
|
from hatchet_sdk.contracts.events_pb2 import (
|
|
12
13
|
BulkPushEventRequest,
|
|
13
14
|
Event,
|
|
@@ -16,20 +17,18 @@ from hatchet_sdk.contracts.events_pb2 import (
|
|
|
16
17
|
PutStreamEventRequest,
|
|
17
18
|
)
|
|
18
19
|
from hatchet_sdk.contracts.events_pb2_grpc import EventsServiceStub
|
|
19
|
-
from hatchet_sdk.
|
|
20
|
+
from hatchet_sdk.metadata import get_metadata
|
|
21
|
+
from hatchet_sdk.utils.typing import JSONSerializableMapping
|
|
20
22
|
|
|
21
|
-
from ..loader import ClientConfig
|
|
22
|
-
from ..metadata import get_metadata
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
def new_event(conn, config: ClientConfig):
|
|
24
|
+
def new_event(conn: grpc.Channel, config: ClientConfig) -> "EventClient":
|
|
26
25
|
return EventClient(
|
|
27
|
-
client=EventsServiceStub(conn),
|
|
26
|
+
client=EventsServiceStub(conn), # type: ignore[no-untyped-call]
|
|
28
27
|
config=config,
|
|
29
28
|
)
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
def proto_timestamp_now():
|
|
31
|
+
def proto_timestamp_now() -> timestamp_pb2.Timestamp:
|
|
33
32
|
t = datetime.datetime.now().timestamp()
|
|
34
33
|
seconds = int(t)
|
|
35
34
|
nanos = int(t % 1 * 1e9)
|
|
@@ -37,19 +36,19 @@ def proto_timestamp_now():
|
|
|
37
36
|
return timestamp_pb2.Timestamp(seconds=seconds, nanos=nanos)
|
|
38
37
|
|
|
39
38
|
|
|
40
|
-
class PushEventOptions(
|
|
41
|
-
additional_metadata:
|
|
39
|
+
class PushEventOptions(BaseModel):
|
|
40
|
+
additional_metadata: JSONSerializableMapping = Field(default_factory=dict)
|
|
42
41
|
namespace: str | None = None
|
|
43
42
|
|
|
44
43
|
|
|
45
|
-
class BulkPushEventOptions(
|
|
44
|
+
class BulkPushEventOptions(BaseModel):
|
|
46
45
|
namespace: str | None = None
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
class BulkPushEventWithMetadata(
|
|
48
|
+
class BulkPushEventWithMetadata(BaseModel):
|
|
50
49
|
key: str
|
|
51
|
-
payload:
|
|
52
|
-
additional_metadata:
|
|
50
|
+
payload: JSONSerializableMapping = Field(default_factory=dict)
|
|
51
|
+
additional_metadata: JSONSerializableMapping = Field(default_factory=dict)
|
|
53
52
|
|
|
54
53
|
|
|
55
54
|
class EventClient:
|
|
@@ -58,126 +57,124 @@ class EventClient:
|
|
|
58
57
|
self.token = config.token
|
|
59
58
|
self.namespace = config.namespace
|
|
60
59
|
|
|
61
|
-
async def
|
|
62
|
-
self,
|
|
60
|
+
async def aio_push(
|
|
61
|
+
self,
|
|
62
|
+
event_key: str,
|
|
63
|
+
payload: JSONSerializableMapping,
|
|
64
|
+
options: PushEventOptions = PushEventOptions(),
|
|
63
65
|
) -> Event:
|
|
64
66
|
return await asyncio.to_thread(
|
|
65
67
|
self.push, event_key=event_key, payload=payload, options=options
|
|
66
68
|
)
|
|
67
69
|
|
|
68
|
-
async def
|
|
70
|
+
async def aio_bulk_push(
|
|
69
71
|
self,
|
|
70
|
-
events:
|
|
71
|
-
options:
|
|
72
|
+
events: list[BulkPushEventWithMetadata],
|
|
73
|
+
options: BulkPushEventOptions = BulkPushEventOptions(),
|
|
72
74
|
) -> List[Event]:
|
|
73
75
|
return await asyncio.to_thread(self.bulk_push, events=events, options=options)
|
|
74
76
|
|
|
75
77
|
## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
|
|
76
78
|
@tenacity_retry
|
|
77
|
-
def push(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
):
|
|
85
|
-
namespace = options.pop("namespace")
|
|
86
|
-
|
|
79
|
+
def push(
|
|
80
|
+
self,
|
|
81
|
+
event_key: str,
|
|
82
|
+
payload: JSONSerializableMapping,
|
|
83
|
+
options: PushEventOptions = PushEventOptions(),
|
|
84
|
+
) -> Event:
|
|
85
|
+
namespace = options.namespace or self.namespace
|
|
87
86
|
namespaced_event_key = namespace + event_key
|
|
88
87
|
|
|
89
88
|
try:
|
|
90
|
-
meta =
|
|
91
|
-
meta_bytes = None if meta is None else json.dumps(meta)
|
|
89
|
+
meta = options.additional_metadata
|
|
90
|
+
meta_bytes = None if meta is None else json.dumps(meta)
|
|
92
91
|
except Exception as e:
|
|
93
92
|
raise ValueError(f"Error encoding meta: {e}")
|
|
94
93
|
|
|
95
94
|
try:
|
|
96
|
-
|
|
97
|
-
except
|
|
95
|
+
payload_str = json.dumps(payload)
|
|
96
|
+
except (TypeError, ValueError) as e:
|
|
98
97
|
raise ValueError(f"Error encoding payload: {e}")
|
|
99
98
|
|
|
100
99
|
request = PushEventRequest(
|
|
101
100
|
key=namespaced_event_key,
|
|
102
|
-
payload=
|
|
101
|
+
payload=payload_str,
|
|
103
102
|
eventTimestamp=proto_timestamp_now(),
|
|
104
103
|
additionalMetadata=meta_bytes,
|
|
105
104
|
)
|
|
106
105
|
|
|
107
|
-
return self.client.Push(request, metadata=get_metadata(self.token))
|
|
106
|
+
return cast(Event, self.client.Push(request, metadata=get_metadata(self.token)))
|
|
107
|
+
|
|
108
|
+
def _create_push_event_request(
|
|
109
|
+
self,
|
|
110
|
+
event: BulkPushEventWithMetadata,
|
|
111
|
+
namespace: str,
|
|
112
|
+
) -> PushEventRequest:
|
|
113
|
+
event_key = namespace + event.key
|
|
114
|
+
payload = event.payload
|
|
115
|
+
|
|
116
|
+
meta = event.additional_metadata
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
meta_str = json.dumps(meta)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
raise ValueError(f"Error encoding meta: {e}")
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
serialized_payload = json.dumps(payload)
|
|
125
|
+
except (TypeError, ValueError) as e:
|
|
126
|
+
raise ValueError(f"Error serializing payload: {e}")
|
|
127
|
+
|
|
128
|
+
return PushEventRequest(
|
|
129
|
+
key=event_key,
|
|
130
|
+
payload=serialized_payload,
|
|
131
|
+
eventTimestamp=proto_timestamp_now(),
|
|
132
|
+
additionalMetadata=meta_str,
|
|
133
|
+
)
|
|
108
134
|
|
|
109
135
|
## IMPORTANT: Keep this method's signature in sync with the wrapper in the OTel instrumentor
|
|
110
136
|
@tenacity_retry
|
|
111
137
|
def bulk_push(
|
|
112
138
|
self,
|
|
113
139
|
events: List[BulkPushEventWithMetadata],
|
|
114
|
-
options: BulkPushEventOptions =
|
|
140
|
+
options: BulkPushEventOptions = BulkPushEventOptions(),
|
|
115
141
|
) -> List[Event]:
|
|
116
|
-
namespace = self.namespace
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
namespace = options.pop("namespace")
|
|
124
|
-
|
|
125
|
-
bulk_events = []
|
|
126
|
-
for event in events:
|
|
127
|
-
event_key = namespace + event["key"]
|
|
128
|
-
payload = event["payload"]
|
|
129
|
-
|
|
130
|
-
try:
|
|
131
|
-
meta = event.get("additional_metadata", {})
|
|
132
|
-
meta_bytes = json.dumps(meta).encode("utf-8") if meta else None
|
|
133
|
-
except Exception as e:
|
|
134
|
-
raise ValueError(f"Error encoding meta: {e}")
|
|
135
|
-
|
|
136
|
-
try:
|
|
137
|
-
payload_bytes = json.dumps(payload).encode("utf-8")
|
|
138
|
-
except json.UnicodeEncodeError as e:
|
|
139
|
-
raise ValueError(f"Error encoding payload: {e}")
|
|
140
|
-
|
|
141
|
-
request = PushEventRequest(
|
|
142
|
-
key=event_key,
|
|
143
|
-
payload=payload_bytes,
|
|
144
|
-
eventTimestamp=proto_timestamp_now(),
|
|
145
|
-
additionalMetadata=meta_bytes,
|
|
146
|
-
)
|
|
147
|
-
bulk_events.append(request)
|
|
148
|
-
|
|
149
|
-
bulk_request = BulkPushEventRequest(events=bulk_events)
|
|
142
|
+
namespace = options.namespace or self.namespace
|
|
143
|
+
|
|
144
|
+
bulk_request = BulkPushEventRequest(
|
|
145
|
+
events=[
|
|
146
|
+
self._create_push_event_request(event, namespace) for event in events
|
|
147
|
+
]
|
|
148
|
+
)
|
|
150
149
|
|
|
151
150
|
response = self.client.BulkPush(bulk_request, metadata=get_metadata(self.token))
|
|
152
151
|
|
|
153
|
-
return
|
|
152
|
+
return cast(
|
|
153
|
+
list[Event],
|
|
154
|
+
response.events,
|
|
155
|
+
)
|
|
154
156
|
|
|
155
|
-
def log(self, message: str, step_run_id: str):
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
157
|
+
def log(self, message: str, step_run_id: str) -> None:
|
|
158
|
+
request = PutLogRequest(
|
|
159
|
+
stepRunId=step_run_id,
|
|
160
|
+
createdAt=proto_timestamp_now(),
|
|
161
|
+
message=message,
|
|
162
|
+
)
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
except Exception as e:
|
|
165
|
-
raise ValueError(f"Error logging: {e}")
|
|
164
|
+
self.client.PutLog(request, metadata=get_metadata(self.token))
|
|
166
165
|
|
|
167
|
-
def stream(self, data: str | bytes, step_run_id: str):
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
except Exception as e:
|
|
183
|
-
raise ValueError(f"Error putting stream event: {e}")
|
|
166
|
+
def stream(self, data: str | bytes, step_run_id: str) -> None:
|
|
167
|
+
if isinstance(data, str):
|
|
168
|
+
data_bytes = data.encode("utf-8")
|
|
169
|
+
elif isinstance(data, bytes):
|
|
170
|
+
data_bytes = data
|
|
171
|
+
else:
|
|
172
|
+
raise ValueError("Invalid data type. Expected str, bytes, or file.")
|
|
173
|
+
|
|
174
|
+
request = PutStreamEventRequest(
|
|
175
|
+
stepRunId=step_run_id,
|
|
176
|
+
createdAt=proto_timestamp_now(),
|
|
177
|
+
message=data_bytes,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
self.client.PutStreamEvent(request, metadata=get_metadata(self.token))
|