hatchet-sdk 1.18.1__py3-none-any.whl → 1.20.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.
Potentially problematic release.
This version of hatchet-sdk might be problematic. Click here for more details.
- hatchet_sdk/clients/dispatcher/action_listener.py +0 -1
- hatchet_sdk/clients/dispatcher/dispatcher.py +0 -30
- hatchet_sdk/hatchet.py +0 -20
- hatchet_sdk/opentelemetry/instrumentor.py +1 -27
- hatchet_sdk/runnables/action.py +2 -5
- hatchet_sdk/runnables/task.py +0 -1
- hatchet_sdk/utils/opentelemetry.py +0 -1
- hatchet_sdk/worker/action_listener_process.py +0 -29
- hatchet_sdk/worker/runner/runner.py +1 -105
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/METADATA +2 -3
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/RECORD +13 -234
- hatchet_sdk/v0/__init__.py +0 -251
- hatchet_sdk/v0/client.py +0 -119
- hatchet_sdk/v0/clients/admin.py +0 -541
- hatchet_sdk/v0/clients/dispatcher/action_listener.py +0 -422
- hatchet_sdk/v0/clients/dispatcher/dispatcher.py +0 -204
- hatchet_sdk/v0/clients/event_ts.py +0 -28
- hatchet_sdk/v0/clients/events.py +0 -182
- hatchet_sdk/v0/clients/rest/__init__.py +0 -307
- hatchet_sdk/v0/clients/rest/api/__init__.py +0 -19
- hatchet_sdk/v0/clients/rest/api/api_token_api.py +0 -858
- hatchet_sdk/v0/clients/rest/api/default_api.py +0 -2259
- hatchet_sdk/v0/clients/rest/api/event_api.py +0 -2548
- hatchet_sdk/v0/clients/rest/api/github_api.py +0 -331
- hatchet_sdk/v0/clients/rest/api/healthcheck_api.py +0 -483
- hatchet_sdk/v0/clients/rest/api/log_api.py +0 -449
- hatchet_sdk/v0/clients/rest/api/metadata_api.py +0 -728
- hatchet_sdk/v0/clients/rest/api/rate_limits_api.py +0 -423
- hatchet_sdk/v0/clients/rest/api/slack_api.py +0 -577
- hatchet_sdk/v0/clients/rest/api/sns_api.py +0 -872
- hatchet_sdk/v0/clients/rest/api/step_run_api.py +0 -2202
- hatchet_sdk/v0/clients/rest/api/tenant_api.py +0 -4430
- hatchet_sdk/v0/clients/rest/api/user_api.py +0 -2888
- hatchet_sdk/v0/clients/rest/api/worker_api.py +0 -858
- hatchet_sdk/v0/clients/rest/api/workflow_api.py +0 -6312
- hatchet_sdk/v0/clients/rest/api/workflow_run_api.py +0 -1932
- hatchet_sdk/v0/clients/rest/api/workflow_runs_api.py +0 -610
- hatchet_sdk/v0/clients/rest/api_client.py +0 -759
- hatchet_sdk/v0/clients/rest/api_response.py +0 -22
- hatchet_sdk/v0/clients/rest/configuration.py +0 -611
- hatchet_sdk/v0/clients/rest/exceptions.py +0 -200
- hatchet_sdk/v0/clients/rest/models/__init__.py +0 -274
- hatchet_sdk/v0/clients/rest/models/accept_invite_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/api_error.py +0 -102
- hatchet_sdk/v0/clients/rest/models/api_errors.py +0 -100
- hatchet_sdk/v0/clients/rest/models/api_meta.py +0 -144
- hatchet_sdk/v0/clients/rest/models/api_meta_auth.py +0 -85
- hatchet_sdk/v0/clients/rest/models/api_meta_integration.py +0 -88
- hatchet_sdk/v0/clients/rest/models/api_meta_posthog.py +0 -90
- hatchet_sdk/v0/clients/rest/models/api_resource_meta.py +0 -98
- hatchet_sdk/v0/clients/rest/models/api_token.py +0 -105
- hatchet_sdk/v0/clients/rest/models/bulk_create_event_request.py +0 -100
- hatchet_sdk/v0/clients/rest/models/bulk_create_event_response.py +0 -110
- hatchet_sdk/v0/clients/rest/models/cancel_event_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/cancel_step_run_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/concurrency_limit_strategy.py +0 -39
- hatchet_sdk/v0/clients/rest/models/create_api_token_request.py +0 -92
- hatchet_sdk/v0/clients/rest/models/create_api_token_response.py +0 -83
- hatchet_sdk/v0/clients/rest/models/create_cron_workflow_trigger_request.py +0 -98
- hatchet_sdk/v0/clients/rest/models/create_event_request.py +0 -95
- hatchet_sdk/v0/clients/rest/models/create_pull_request_from_step_run.py +0 -83
- hatchet_sdk/v0/clients/rest/models/create_sns_integration_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/create_tenant_alert_email_group_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/create_tenant_invite_request.py +0 -86
- hatchet_sdk/v0/clients/rest/models/create_tenant_request.py +0 -84
- hatchet_sdk/v0/clients/rest/models/cron_workflows.py +0 -131
- hatchet_sdk/v0/clients/rest/models/cron_workflows_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/cron_workflows_method.py +0 -37
- hatchet_sdk/v0/clients/rest/models/cron_workflows_order_by_field.py +0 -37
- hatchet_sdk/v0/clients/rest/models/event.py +0 -143
- hatchet_sdk/v0/clients/rest/models/event_data.py +0 -83
- hatchet_sdk/v0/clients/rest/models/event_key_list.py +0 -98
- hatchet_sdk/v0/clients/rest/models/event_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/event_order_by_direction.py +0 -37
- hatchet_sdk/v0/clients/rest/models/event_order_by_field.py +0 -36
- hatchet_sdk/v0/clients/rest/models/event_update_cancel200_response.py +0 -85
- hatchet_sdk/v0/clients/rest/models/event_workflow_run_summary.py +0 -116
- hatchet_sdk/v0/clients/rest/models/events.py +0 -110
- hatchet_sdk/v0/clients/rest/models/get_step_run_diff_response.py +0 -100
- hatchet_sdk/v0/clients/rest/models/github_app_installation.py +0 -107
- hatchet_sdk/v0/clients/rest/models/github_branch.py +0 -86
- hatchet_sdk/v0/clients/rest/models/github_repo.py +0 -86
- hatchet_sdk/v0/clients/rest/models/info_get_version200_response.py +0 -83
- hatchet_sdk/v0/clients/rest/models/job.py +0 -132
- hatchet_sdk/v0/clients/rest/models/job_run.py +0 -176
- hatchet_sdk/v0/clients/rest/models/job_run_status.py +0 -41
- hatchet_sdk/v0/clients/rest/models/link_github_repository_request.py +0 -106
- hatchet_sdk/v0/clients/rest/models/list_api_tokens_response.py +0 -110
- hatchet_sdk/v0/clients/rest/models/list_github_app_installations_response.py +0 -112
- hatchet_sdk/v0/clients/rest/models/list_pull_requests_response.py +0 -100
- hatchet_sdk/v0/clients/rest/models/list_slack_webhooks.py +0 -110
- hatchet_sdk/v0/clients/rest/models/list_sns_integrations.py +0 -110
- hatchet_sdk/v0/clients/rest/models/log_line.py +0 -94
- hatchet_sdk/v0/clients/rest/models/log_line_level.py +0 -39
- hatchet_sdk/v0/clients/rest/models/log_line_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/log_line_order_by_direction.py +0 -37
- hatchet_sdk/v0/clients/rest/models/log_line_order_by_field.py +0 -36
- hatchet_sdk/v0/clients/rest/models/pagination_response.py +0 -95
- hatchet_sdk/v0/clients/rest/models/pull_request.py +0 -112
- hatchet_sdk/v0/clients/rest/models/pull_request_state.py +0 -37
- hatchet_sdk/v0/clients/rest/models/queue_metrics.py +0 -97
- hatchet_sdk/v0/clients/rest/models/rate_limit.py +0 -117
- hatchet_sdk/v0/clients/rest/models/rate_limit_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_direction.py +0 -37
- hatchet_sdk/v0/clients/rest/models/rate_limit_order_by_field.py +0 -38
- hatchet_sdk/v0/clients/rest/models/recent_step_runs.py +0 -118
- hatchet_sdk/v0/clients/rest/models/reject_invite_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/replay_event_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/replay_workflow_runs_response.py +0 -100
- hatchet_sdk/v0/clients/rest/models/rerun_step_run_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/schedule_workflow_run_request.py +0 -92
- hatchet_sdk/v0/clients/rest/models/scheduled_run_status.py +0 -42
- hatchet_sdk/v0/clients/rest/models/scheduled_workflows.py +0 -149
- hatchet_sdk/v0/clients/rest/models/scheduled_workflows_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/scheduled_workflows_method.py +0 -37
- hatchet_sdk/v0/clients/rest/models/scheduled_workflows_order_by_field.py +0 -37
- hatchet_sdk/v0/clients/rest/models/semaphore_slots.py +0 -113
- hatchet_sdk/v0/clients/rest/models/slack_webhook.py +0 -127
- hatchet_sdk/v0/clients/rest/models/sns_integration.py +0 -114
- hatchet_sdk/v0/clients/rest/models/step.py +0 -123
- hatchet_sdk/v0/clients/rest/models/step_run.py +0 -202
- hatchet_sdk/v0/clients/rest/models/step_run_archive.py +0 -142
- hatchet_sdk/v0/clients/rest/models/step_run_archive_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/step_run_diff.py +0 -91
- hatchet_sdk/v0/clients/rest/models/step_run_event.py +0 -122
- hatchet_sdk/v0/clients/rest/models/step_run_event_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/step_run_event_reason.py +0 -52
- hatchet_sdk/v0/clients/rest/models/step_run_event_severity.py +0 -38
- hatchet_sdk/v0/clients/rest/models/step_run_status.py +0 -44
- hatchet_sdk/v0/clients/rest/models/tenant.py +0 -118
- hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group.py +0 -98
- hatchet_sdk/v0/clients/rest/models/tenant_alert_email_group_list.py +0 -112
- hatchet_sdk/v0/clients/rest/models/tenant_alerting_settings.py +0 -143
- hatchet_sdk/v0/clients/rest/models/tenant_invite.py +0 -120
- hatchet_sdk/v0/clients/rest/models/tenant_invite_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/tenant_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/tenant_member.py +0 -123
- hatchet_sdk/v0/clients/rest/models/tenant_member_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/tenant_member_role.py +0 -38
- hatchet_sdk/v0/clients/rest/models/tenant_queue_metrics.py +0 -116
- hatchet_sdk/v0/clients/rest/models/tenant_resource.py +0 -40
- hatchet_sdk/v0/clients/rest/models/tenant_resource_limit.py +0 -135
- hatchet_sdk/v0/clients/rest/models/tenant_resource_policy.py +0 -102
- hatchet_sdk/v0/clients/rest/models/tenant_step_run_queue_metrics.py +0 -83
- hatchet_sdk/v0/clients/rest/models/trigger_workflow_run_request.py +0 -91
- hatchet_sdk/v0/clients/rest/models/update_tenant_alert_email_group_request.py +0 -83
- hatchet_sdk/v0/clients/rest/models/update_tenant_invite_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/update_tenant_request.py +0 -137
- hatchet_sdk/v0/clients/rest/models/update_worker_request.py +0 -87
- hatchet_sdk/v0/clients/rest/models/user.py +0 -126
- hatchet_sdk/v0/clients/rest/models/user_change_password_request.py +0 -88
- hatchet_sdk/v0/clients/rest/models/user_login_request.py +0 -86
- hatchet_sdk/v0/clients/rest/models/user_register_request.py +0 -91
- hatchet_sdk/v0/clients/rest/models/user_tenant_memberships_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/user_tenant_public.py +0 -86
- hatchet_sdk/v0/clients/rest/models/webhook_worker.py +0 -100
- hatchet_sdk/v0/clients/rest/models/webhook_worker_create_request.py +0 -94
- hatchet_sdk/v0/clients/rest/models/webhook_worker_create_response.py +0 -98
- hatchet_sdk/v0/clients/rest/models/webhook_worker_created.py +0 -102
- hatchet_sdk/v0/clients/rest/models/webhook_worker_list_response.py +0 -110
- hatchet_sdk/v0/clients/rest/models/webhook_worker_request.py +0 -102
- hatchet_sdk/v0/clients/rest/models/webhook_worker_request_list_response.py +0 -104
- hatchet_sdk/v0/clients/rest/models/webhook_worker_request_method.py +0 -38
- hatchet_sdk/v0/clients/rest/models/worker.py +0 -239
- hatchet_sdk/v0/clients/rest/models/worker_label.py +0 -102
- hatchet_sdk/v0/clients/rest/models/worker_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/worker_runtime_info.py +0 -103
- hatchet_sdk/v0/clients/rest/models/worker_runtime_sdks.py +0 -38
- hatchet_sdk/v0/clients/rest/models/worker_type.py +0 -38
- hatchet_sdk/v0/clients/rest/models/workflow.py +0 -165
- hatchet_sdk/v0/clients/rest/models/workflow_concurrency.py +0 -107
- hatchet_sdk/v0/clients/rest/models/workflow_deployment_config.py +0 -136
- hatchet_sdk/v0/clients/rest/models/workflow_kind.py +0 -38
- hatchet_sdk/v0/clients/rest/models/workflow_list.py +0 -120
- hatchet_sdk/v0/clients/rest/models/workflow_metrics.py +0 -97
- hatchet_sdk/v0/clients/rest/models/workflow_run.py +0 -188
- hatchet_sdk/v0/clients/rest/models/workflow_run_cancel200_response.py +0 -85
- hatchet_sdk/v0/clients/rest/models/workflow_run_list.py +0 -110
- hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_direction.py +0 -37
- hatchet_sdk/v0/clients/rest/models/workflow_run_order_by_field.py +0 -39
- hatchet_sdk/v0/clients/rest/models/workflow_run_shape.py +0 -186
- hatchet_sdk/v0/clients/rest/models/workflow_run_status.py +0 -42
- hatchet_sdk/v0/clients/rest/models/workflow_run_triggered_by.py +0 -112
- hatchet_sdk/v0/clients/rest/models/workflow_runs_cancel_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics.py +0 -94
- hatchet_sdk/v0/clients/rest/models/workflow_runs_metrics_counts.py +0 -104
- hatchet_sdk/v0/clients/rest/models/workflow_tag.py +0 -84
- hatchet_sdk/v0/clients/rest/models/workflow_trigger_cron_ref.py +0 -86
- hatchet_sdk/v0/clients/rest/models/workflow_trigger_event_ref.py +0 -86
- hatchet_sdk/v0/clients/rest/models/workflow_triggers.py +0 -141
- hatchet_sdk/v0/clients/rest/models/workflow_update_request.py +0 -85
- hatchet_sdk/v0/clients/rest/models/workflow_version.py +0 -170
- hatchet_sdk/v0/clients/rest/models/workflow_version_concurrency.py +0 -114
- hatchet_sdk/v0/clients/rest/models/workflow_version_definition.py +0 -85
- hatchet_sdk/v0/clients/rest/models/workflow_version_meta.py +0 -123
- hatchet_sdk/v0/clients/rest/models/workflow_workers_count.py +0 -95
- hatchet_sdk/v0/clients/rest/rest.py +0 -187
- hatchet_sdk/v0/clients/rest/tenacity_utils.py +0 -39
- hatchet_sdk/v0/clients/rest_client.py +0 -622
- hatchet_sdk/v0/clients/run_event_listener.py +0 -260
- hatchet_sdk/v0/clients/workflow_listener.py +0 -277
- hatchet_sdk/v0/connection.py +0 -63
- hatchet_sdk/v0/context/__init__.py +0 -1
- hatchet_sdk/v0/context/context.py +0 -446
- hatchet_sdk/v0/context/worker_context.py +0 -28
- hatchet_sdk/v0/features/cron.py +0 -286
- hatchet_sdk/v0/features/scheduled.py +0 -248
- hatchet_sdk/v0/hatchet.py +0 -310
- hatchet_sdk/v0/labels.py +0 -10
- hatchet_sdk/v0/loader.py +0 -244
- hatchet_sdk/v0/metadata.py +0 -2
- hatchet_sdk/v0/opentelemetry/instrumentor.py +0 -393
- hatchet_sdk/v0/rate_limit.py +0 -126
- hatchet_sdk/v0/semver.py +0 -30
- hatchet_sdk/v0/token.py +0 -27
- hatchet_sdk/v0/utils/aio_utils.py +0 -137
- hatchet_sdk/v0/utils/backoff.py +0 -9
- hatchet_sdk/v0/utils/types.py +0 -8
- hatchet_sdk/v0/utils/typing.py +0 -12
- hatchet_sdk/v0/v2/callable.py +0 -202
- hatchet_sdk/v0/v2/concurrency.py +0 -47
- hatchet_sdk/v0/v2/hatchet.py +0 -224
- hatchet_sdk/v0/worker/__init__.py +0 -1
- hatchet_sdk/v0/worker/action_listener_process.py +0 -294
- hatchet_sdk/v0/worker/runner/run_loop_manager.py +0 -112
- hatchet_sdk/v0/worker/runner/runner.py +0 -460
- hatchet_sdk/v0/worker/runner/utils/capture_logs.py +0 -81
- hatchet_sdk/v0/worker/runner/utils/error_with_traceback.py +0 -6
- hatchet_sdk/v0/worker/worker.py +0 -391
- hatchet_sdk/v0/workflow.py +0 -261
- hatchet_sdk/v0/workflow_run.py +0 -59
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/WHEEL +0 -0
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.20.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import json
|
|
3
|
-
import time
|
|
4
|
-
from dataclasses import dataclass, field
|
|
5
|
-
from typing import Any, AsyncGenerator, List, Optional
|
|
6
|
-
|
|
7
|
-
import grpc
|
|
8
|
-
from grpc._cython import cygrpc
|
|
9
|
-
|
|
10
|
-
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
11
|
-
ActionType,
|
|
12
|
-
AssignedAction,
|
|
13
|
-
HeartbeatRequest,
|
|
14
|
-
WorkerLabels,
|
|
15
|
-
WorkerListenRequest,
|
|
16
|
-
WorkerUnsubscribeRequest,
|
|
17
|
-
)
|
|
18
|
-
from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
|
|
19
|
-
from hatchet_sdk.logger import logger
|
|
20
|
-
from hatchet_sdk.v0.clients.event_ts import ThreadSafeEvent, read_with_interrupt
|
|
21
|
-
from hatchet_sdk.v0.clients.run_event_listener import (
|
|
22
|
-
DEFAULT_ACTION_LISTENER_RETRY_INTERVAL,
|
|
23
|
-
)
|
|
24
|
-
from hatchet_sdk.v0.connection import new_conn
|
|
25
|
-
from hatchet_sdk.v0.utils.backoff import exp_backoff_sleep
|
|
26
|
-
|
|
27
|
-
from ...loader import ClientConfig
|
|
28
|
-
from ...metadata import get_metadata
|
|
29
|
-
from ..events import proto_timestamp_now
|
|
30
|
-
|
|
31
|
-
DEFAULT_ACTION_TIMEOUT = 600 # seconds
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
DEFAULT_ACTION_LISTENER_RETRY_INTERVAL = 5 # seconds
|
|
35
|
-
DEFAULT_ACTION_LISTENER_RETRY_COUNT = 15
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@dataclass
|
|
39
|
-
class GetActionListenerRequest:
|
|
40
|
-
worker_name: str
|
|
41
|
-
services: List[str]
|
|
42
|
-
actions: List[str]
|
|
43
|
-
max_runs: Optional[int] = None
|
|
44
|
-
_labels: dict[str, str | int] = field(default_factory=dict)
|
|
45
|
-
|
|
46
|
-
labels: dict[str, WorkerLabels] = field(init=False)
|
|
47
|
-
|
|
48
|
-
def __post_init__(self):
|
|
49
|
-
self.labels = {}
|
|
50
|
-
|
|
51
|
-
for key, value in self._labels.items():
|
|
52
|
-
if isinstance(value, int):
|
|
53
|
-
self.labels[key] = WorkerLabels(intValue=value)
|
|
54
|
-
else:
|
|
55
|
-
self.labels[key] = WorkerLabels(strValue=str(value))
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@dataclass
|
|
59
|
-
class Action:
|
|
60
|
-
worker_id: str
|
|
61
|
-
tenant_id: str
|
|
62
|
-
workflow_run_id: str
|
|
63
|
-
get_group_key_run_id: str
|
|
64
|
-
job_id: str
|
|
65
|
-
job_name: str
|
|
66
|
-
job_run_id: str
|
|
67
|
-
step_id: str
|
|
68
|
-
step_run_id: str
|
|
69
|
-
action_id: str
|
|
70
|
-
action_payload: str
|
|
71
|
-
action_type: ActionType
|
|
72
|
-
retry_count: int
|
|
73
|
-
additional_metadata: dict[str, str] | None = None
|
|
74
|
-
|
|
75
|
-
child_workflow_index: int | None = None
|
|
76
|
-
child_workflow_key: str | None = None
|
|
77
|
-
parent_workflow_run_id: str | None = None
|
|
78
|
-
|
|
79
|
-
def __post_init__(self):
|
|
80
|
-
if isinstance(self.additional_metadata, str) and self.additional_metadata != "":
|
|
81
|
-
try:
|
|
82
|
-
self.additional_metadata = json.loads(self.additional_metadata)
|
|
83
|
-
except json.JSONDecodeError:
|
|
84
|
-
# If JSON decoding fails, keep the original string
|
|
85
|
-
pass
|
|
86
|
-
|
|
87
|
-
# Ensure additional_metadata is always a dictionary
|
|
88
|
-
if not isinstance(self.additional_metadata, dict):
|
|
89
|
-
self.additional_metadata = {}
|
|
90
|
-
|
|
91
|
-
@property
|
|
92
|
-
def otel_attributes(self) -> dict[str, str | int]:
|
|
93
|
-
try:
|
|
94
|
-
payload_str = json.dumps(self.action_payload, default=str)
|
|
95
|
-
except Exception:
|
|
96
|
-
payload_str = str(self.action_payload)
|
|
97
|
-
|
|
98
|
-
attrs: dict[str, str | int | None] = {
|
|
99
|
-
"hatchet.tenant_id": self.tenant_id,
|
|
100
|
-
"hatchet.worker_id": self.worker_id,
|
|
101
|
-
"hatchet.workflow_run_id": self.workflow_run_id,
|
|
102
|
-
"hatchet.step_id": self.step_id,
|
|
103
|
-
"hatchet.step_run_id": self.step_run_id,
|
|
104
|
-
"hatchet.retry_count": self.retry_count,
|
|
105
|
-
"hatchet.parent_workflow_run_id": self.parent_workflow_run_id,
|
|
106
|
-
"hatchet.child_workflow_index": self.child_workflow_index,
|
|
107
|
-
"hatchet.child_workflow_key": self.child_workflow_key,
|
|
108
|
-
"hatchet.action_payload": payload_str,
|
|
109
|
-
"hatchet.workflow_name": self.job_name,
|
|
110
|
-
"hatchet.action_name": self.action_id,
|
|
111
|
-
"hatchet.get_group_key_run_id": self.get_group_key_run_id,
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return {k: v for k, v in attrs.items() if v}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
START_STEP_RUN = 0
|
|
118
|
-
CANCEL_STEP_RUN = 1
|
|
119
|
-
START_GET_GROUP_KEY = 2
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@dataclass
|
|
123
|
-
class ActionListener:
|
|
124
|
-
config: ClientConfig
|
|
125
|
-
worker_id: str
|
|
126
|
-
|
|
127
|
-
client: DispatcherStub = field(init=False)
|
|
128
|
-
aio_client: DispatcherStub = field(init=False)
|
|
129
|
-
token: str = field(init=False)
|
|
130
|
-
retries: int = field(default=0, init=False)
|
|
131
|
-
last_connection_attempt: float = field(default=0, init=False)
|
|
132
|
-
last_heartbeat_succeeded: bool = field(default=True, init=False)
|
|
133
|
-
time_last_hb_succeeded: float = field(default=9999999999999, init=False)
|
|
134
|
-
heartbeat_task: Optional[asyncio.Task] = field(default=None, init=False)
|
|
135
|
-
run_heartbeat: bool = field(default=True, init=False)
|
|
136
|
-
listen_strategy: str = field(default="v2", init=False)
|
|
137
|
-
stop_signal: bool = field(default=False, init=False)
|
|
138
|
-
|
|
139
|
-
missed_heartbeats: int = field(default=0, init=False)
|
|
140
|
-
|
|
141
|
-
def __post_init__(self):
|
|
142
|
-
self.client = DispatcherStub(new_conn(self.config))
|
|
143
|
-
self.aio_client = DispatcherStub(new_conn(self.config, True))
|
|
144
|
-
self.token = self.config.token
|
|
145
|
-
|
|
146
|
-
def is_healthy(self):
|
|
147
|
-
return self.last_heartbeat_succeeded
|
|
148
|
-
|
|
149
|
-
async def heartbeat(self):
|
|
150
|
-
# send a heartbeat every 4 seconds
|
|
151
|
-
heartbeat_delay = 4
|
|
152
|
-
|
|
153
|
-
while True:
|
|
154
|
-
if not self.run_heartbeat:
|
|
155
|
-
break
|
|
156
|
-
|
|
157
|
-
try:
|
|
158
|
-
logger.debug("sending heartbeat")
|
|
159
|
-
await self.aio_client.Heartbeat(
|
|
160
|
-
HeartbeatRequest(
|
|
161
|
-
workerId=self.worker_id,
|
|
162
|
-
heartbeatAt=proto_timestamp_now(),
|
|
163
|
-
),
|
|
164
|
-
timeout=5,
|
|
165
|
-
metadata=get_metadata(self.token),
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
if self.last_heartbeat_succeeded is False:
|
|
169
|
-
logger.info("listener established")
|
|
170
|
-
|
|
171
|
-
now = time.time()
|
|
172
|
-
diff = now - self.time_last_hb_succeeded
|
|
173
|
-
if diff > heartbeat_delay + 1:
|
|
174
|
-
logger.warn(
|
|
175
|
-
f"time since last successful heartbeat: {diff:.2f}s, expects {heartbeat_delay}s"
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
self.last_heartbeat_succeeded = True
|
|
179
|
-
self.time_last_hb_succeeded = now
|
|
180
|
-
self.missed_heartbeats = 0
|
|
181
|
-
except grpc.RpcError as e:
|
|
182
|
-
self.missed_heartbeats = self.missed_heartbeats + 1
|
|
183
|
-
self.last_heartbeat_succeeded = False
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
e.code() == grpc.StatusCode.UNAVAILABLE
|
|
187
|
-
or e.code() == grpc.StatusCode.FAILED_PRECONDITION
|
|
188
|
-
):
|
|
189
|
-
# todo case on "recvmsg:Connection reset by peer" for updates?
|
|
190
|
-
if self.missed_heartbeats >= 3:
|
|
191
|
-
# we don't reraise the error here, as we don't want to stop the heartbeat thread
|
|
192
|
-
logger.error(
|
|
193
|
-
f"⛔️ failed heartbeat ({self.missed_heartbeats}): {e.details()}"
|
|
194
|
-
)
|
|
195
|
-
elif self.missed_heartbeats > 1:
|
|
196
|
-
logger.warning(
|
|
197
|
-
f"failed to send heartbeat ({self.missed_heartbeats}): {e.details()}"
|
|
198
|
-
)
|
|
199
|
-
else:
|
|
200
|
-
logger.error(f"failed to send heartbeat: {e}")
|
|
201
|
-
|
|
202
|
-
if self.interrupt is not None:
|
|
203
|
-
self.interrupt.set()
|
|
204
|
-
|
|
205
|
-
if e.code() == grpc.StatusCode.UNIMPLEMENTED:
|
|
206
|
-
break
|
|
207
|
-
await asyncio.sleep(heartbeat_delay)
|
|
208
|
-
|
|
209
|
-
async def start_heartbeater(self):
|
|
210
|
-
if self.heartbeat_task is not None:
|
|
211
|
-
return
|
|
212
|
-
|
|
213
|
-
try:
|
|
214
|
-
loop = asyncio.get_event_loop()
|
|
215
|
-
except RuntimeError as e:
|
|
216
|
-
if str(e).startswith("There is no current event loop in thread"):
|
|
217
|
-
loop = asyncio.new_event_loop()
|
|
218
|
-
asyncio.set_event_loop(loop)
|
|
219
|
-
else:
|
|
220
|
-
raise e
|
|
221
|
-
self.heartbeat_task = loop.create_task(self.heartbeat())
|
|
222
|
-
|
|
223
|
-
def __aiter__(self):
|
|
224
|
-
return self._generator()
|
|
225
|
-
|
|
226
|
-
async def _generator(self) -> AsyncGenerator[Action, None]:
|
|
227
|
-
listener = None
|
|
228
|
-
|
|
229
|
-
while not self.stop_signal:
|
|
230
|
-
if listener is not None:
|
|
231
|
-
listener.cancel()
|
|
232
|
-
|
|
233
|
-
try:
|
|
234
|
-
listener = await self.get_listen_client()
|
|
235
|
-
except Exception:
|
|
236
|
-
logger.info("closing action listener loop")
|
|
237
|
-
yield None
|
|
238
|
-
|
|
239
|
-
try:
|
|
240
|
-
while not self.stop_signal:
|
|
241
|
-
self.interrupt = ThreadSafeEvent()
|
|
242
|
-
t = asyncio.create_task(
|
|
243
|
-
read_with_interrupt(listener, self.interrupt)
|
|
244
|
-
)
|
|
245
|
-
await self.interrupt.wait()
|
|
246
|
-
|
|
247
|
-
if not t.done():
|
|
248
|
-
# print a warning
|
|
249
|
-
logger.warning(
|
|
250
|
-
"Interrupted read_with_interrupt task of action listener"
|
|
251
|
-
)
|
|
252
|
-
|
|
253
|
-
t.cancel()
|
|
254
|
-
listener.cancel()
|
|
255
|
-
break
|
|
256
|
-
|
|
257
|
-
assigned_action = t.result()
|
|
258
|
-
|
|
259
|
-
if assigned_action is cygrpc.EOF:
|
|
260
|
-
self.retries = self.retries + 1
|
|
261
|
-
break
|
|
262
|
-
|
|
263
|
-
self.retries = 0
|
|
264
|
-
assigned_action: AssignedAction
|
|
265
|
-
|
|
266
|
-
# Process the received action
|
|
267
|
-
action_type = self.map_action_type(assigned_action.actionType)
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
assigned_action.actionPayload is None
|
|
271
|
-
or assigned_action.actionPayload == ""
|
|
272
|
-
):
|
|
273
|
-
action_payload = None
|
|
274
|
-
else:
|
|
275
|
-
action_payload = self.parse_action_payload(
|
|
276
|
-
assigned_action.actionPayload
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
action = Action(
|
|
280
|
-
tenant_id=assigned_action.tenantId,
|
|
281
|
-
worker_id=self.worker_id,
|
|
282
|
-
workflow_run_id=assigned_action.workflowRunId,
|
|
283
|
-
get_group_key_run_id=assigned_action.getGroupKeyRunId,
|
|
284
|
-
job_id=assigned_action.jobId,
|
|
285
|
-
job_name=assigned_action.jobName,
|
|
286
|
-
job_run_id=assigned_action.jobRunId,
|
|
287
|
-
step_id=assigned_action.stepId,
|
|
288
|
-
step_run_id=assigned_action.stepRunId,
|
|
289
|
-
action_id=assigned_action.actionId,
|
|
290
|
-
action_payload=action_payload,
|
|
291
|
-
action_type=action_type,
|
|
292
|
-
retry_count=assigned_action.retryCount,
|
|
293
|
-
additional_metadata=assigned_action.additional_metadata,
|
|
294
|
-
child_workflow_index=assigned_action.child_workflow_index,
|
|
295
|
-
child_workflow_key=assigned_action.child_workflow_key,
|
|
296
|
-
parent_workflow_run_id=assigned_action.parent_workflow_run_id,
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
yield action
|
|
300
|
-
except grpc.RpcError as e:
|
|
301
|
-
self.last_heartbeat_succeeded = False
|
|
302
|
-
|
|
303
|
-
# Handle different types of errors
|
|
304
|
-
if e.code() == grpc.StatusCode.CANCELLED:
|
|
305
|
-
# Context cancelled, unsubscribe and close
|
|
306
|
-
logger.debug("Context cancelled, closing listener")
|
|
307
|
-
elif e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
|
|
308
|
-
logger.info("Deadline exceeded, retrying subscription")
|
|
309
|
-
elif (
|
|
310
|
-
self.listen_strategy == "v2"
|
|
311
|
-
and e.code() == grpc.StatusCode.UNIMPLEMENTED
|
|
312
|
-
):
|
|
313
|
-
# ListenV2 is not available, fallback to Listen
|
|
314
|
-
self.listen_strategy = "v1"
|
|
315
|
-
self.run_heartbeat = False
|
|
316
|
-
logger.info("ListenV2 not available, falling back to Listen")
|
|
317
|
-
else:
|
|
318
|
-
# TODO retry
|
|
319
|
-
if e.code() == grpc.StatusCode.UNAVAILABLE:
|
|
320
|
-
logger.error(f"action listener error: {e.details()}")
|
|
321
|
-
else:
|
|
322
|
-
# Unknown error, report and break
|
|
323
|
-
logger.error(f"action listener error: {e}")
|
|
324
|
-
|
|
325
|
-
self.retries = self.retries + 1
|
|
326
|
-
|
|
327
|
-
def parse_action_payload(self, payload: str):
|
|
328
|
-
try:
|
|
329
|
-
payload_data = json.loads(payload)
|
|
330
|
-
except json.JSONDecodeError as e:
|
|
331
|
-
raise ValueError(f"Error decoding payload: {e}")
|
|
332
|
-
return payload_data
|
|
333
|
-
|
|
334
|
-
def map_action_type(self, action_type):
|
|
335
|
-
if action_type == ActionType.START_STEP_RUN:
|
|
336
|
-
return START_STEP_RUN
|
|
337
|
-
elif action_type == ActionType.CANCEL_STEP_RUN:
|
|
338
|
-
return CANCEL_STEP_RUN
|
|
339
|
-
elif action_type == ActionType.START_GET_GROUP_KEY:
|
|
340
|
-
return START_GET_GROUP_KEY
|
|
341
|
-
else:
|
|
342
|
-
# logger.error(f"Unknown action type: {action_type}")
|
|
343
|
-
return None
|
|
344
|
-
|
|
345
|
-
async def get_listen_client(self):
|
|
346
|
-
current_time = int(time.time())
|
|
347
|
-
|
|
348
|
-
if (
|
|
349
|
-
current_time - self.last_connection_attempt
|
|
350
|
-
> DEFAULT_ACTION_LISTENER_RETRY_INTERVAL
|
|
351
|
-
):
|
|
352
|
-
# reset retries if last connection was long lived
|
|
353
|
-
self.retries = 0
|
|
354
|
-
|
|
355
|
-
if self.retries > DEFAULT_ACTION_LISTENER_RETRY_COUNT:
|
|
356
|
-
# TODO this is the problem case...
|
|
357
|
-
logger.error(
|
|
358
|
-
f"could not establish action listener connection after {DEFAULT_ACTION_LISTENER_RETRY_COUNT} retries"
|
|
359
|
-
)
|
|
360
|
-
self.run_heartbeat = False
|
|
361
|
-
raise Exception("retry_exhausted")
|
|
362
|
-
elif self.retries >= 1:
|
|
363
|
-
# logger.info
|
|
364
|
-
# if we are retrying, we wait for a bit. this should eventually be replaced with exp backoff + jitter
|
|
365
|
-
await exp_backoff_sleep(
|
|
366
|
-
self.retries, DEFAULT_ACTION_LISTENER_RETRY_INTERVAL
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
logger.info(
|
|
370
|
-
f"action listener connection interrupted, retrying... ({self.retries}/{DEFAULT_ACTION_LISTENER_RETRY_COUNT})"
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
self.aio_client = DispatcherStub(new_conn(self.config, True))
|
|
374
|
-
|
|
375
|
-
if self.listen_strategy == "v2":
|
|
376
|
-
# we should await for the listener to be established before
|
|
377
|
-
# starting the heartbeater
|
|
378
|
-
listener = self.aio_client.ListenV2(
|
|
379
|
-
WorkerListenRequest(workerId=self.worker_id),
|
|
380
|
-
timeout=self.config.listener_v2_timeout,
|
|
381
|
-
metadata=get_metadata(self.token),
|
|
382
|
-
)
|
|
383
|
-
await self.start_heartbeater()
|
|
384
|
-
else:
|
|
385
|
-
# if ListenV2 is not available, fallback to Listen
|
|
386
|
-
listener = self.aio_client.Listen(
|
|
387
|
-
WorkerListenRequest(workerId=self.worker_id),
|
|
388
|
-
timeout=DEFAULT_ACTION_TIMEOUT,
|
|
389
|
-
metadata=get_metadata(self.token),
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
self.last_connection_attempt = current_time
|
|
393
|
-
|
|
394
|
-
return listener
|
|
395
|
-
|
|
396
|
-
def cleanup(self):
|
|
397
|
-
self.run_heartbeat = False
|
|
398
|
-
self.heartbeat_task.cancel()
|
|
399
|
-
|
|
400
|
-
try:
|
|
401
|
-
self.unregister()
|
|
402
|
-
except Exception as e:
|
|
403
|
-
logger.error(f"failed to unregister: {e}")
|
|
404
|
-
|
|
405
|
-
if self.interrupt:
|
|
406
|
-
self.interrupt.set()
|
|
407
|
-
|
|
408
|
-
def unregister(self):
|
|
409
|
-
self.run_heartbeat = False
|
|
410
|
-
self.heartbeat_task.cancel()
|
|
411
|
-
|
|
412
|
-
try:
|
|
413
|
-
req = self.aio_client.Unsubscribe(
|
|
414
|
-
WorkerUnsubscribeRequest(workerId=self.worker_id),
|
|
415
|
-
timeout=5,
|
|
416
|
-
metadata=get_metadata(self.token),
|
|
417
|
-
)
|
|
418
|
-
if self.interrupt is not None:
|
|
419
|
-
self.interrupt.set()
|
|
420
|
-
return req
|
|
421
|
-
except grpc.RpcError as e:
|
|
422
|
-
raise Exception(f"Failed to unsubscribe: {e}")
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
from typing import Any, cast
|
|
2
|
-
|
|
3
|
-
from google.protobuf.timestamp_pb2 import Timestamp
|
|
4
|
-
|
|
5
|
-
from hatchet_sdk.contracts.dispatcher_pb2 import (
|
|
6
|
-
STEP_EVENT_TYPE_COMPLETED,
|
|
7
|
-
STEP_EVENT_TYPE_FAILED,
|
|
8
|
-
ActionEventResponse,
|
|
9
|
-
GroupKeyActionEvent,
|
|
10
|
-
GroupKeyActionEventType,
|
|
11
|
-
OverridesData,
|
|
12
|
-
RefreshTimeoutRequest,
|
|
13
|
-
ReleaseSlotRequest,
|
|
14
|
-
StepActionEvent,
|
|
15
|
-
StepActionEventType,
|
|
16
|
-
UpsertWorkerLabelsRequest,
|
|
17
|
-
WorkerLabels,
|
|
18
|
-
WorkerRegisterRequest,
|
|
19
|
-
WorkerRegisterResponse,
|
|
20
|
-
)
|
|
21
|
-
from hatchet_sdk.contracts.dispatcher_pb2_grpc import DispatcherStub
|
|
22
|
-
from hatchet_sdk.v0.clients.dispatcher.action_listener import (
|
|
23
|
-
Action,
|
|
24
|
-
ActionListener,
|
|
25
|
-
GetActionListenerRequest,
|
|
26
|
-
)
|
|
27
|
-
from hatchet_sdk.v0.clients.rest.tenacity_utils import tenacity_retry
|
|
28
|
-
from hatchet_sdk.v0.connection import new_conn
|
|
29
|
-
|
|
30
|
-
from ...loader import ClientConfig
|
|
31
|
-
from ...metadata import get_metadata
|
|
32
|
-
|
|
33
|
-
DEFAULT_REGISTER_TIMEOUT = 30
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def new_dispatcher(config: ClientConfig) -> "DispatcherClient":
|
|
37
|
-
return DispatcherClient(config=config)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class DispatcherClient:
|
|
41
|
-
config: ClientConfig
|
|
42
|
-
|
|
43
|
-
def __init__(self, config: ClientConfig):
|
|
44
|
-
conn = new_conn(config)
|
|
45
|
-
self.client = DispatcherStub(conn) # type: ignore[no-untyped-call]
|
|
46
|
-
|
|
47
|
-
aio_conn = new_conn(config, True)
|
|
48
|
-
self.aio_client = DispatcherStub(aio_conn) # type: ignore[no-untyped-call]
|
|
49
|
-
self.token = config.token
|
|
50
|
-
self.config = config
|
|
51
|
-
|
|
52
|
-
async def get_action_listener(
|
|
53
|
-
self, req: GetActionListenerRequest
|
|
54
|
-
) -> ActionListener:
|
|
55
|
-
|
|
56
|
-
# Override labels with the preset labels
|
|
57
|
-
preset_labels = self.config.worker_preset_labels
|
|
58
|
-
|
|
59
|
-
for key, value in preset_labels.items():
|
|
60
|
-
req.labels[key] = WorkerLabels(strValue=str(value))
|
|
61
|
-
|
|
62
|
-
# Register the worker
|
|
63
|
-
response: WorkerRegisterResponse = await self.aio_client.Register(
|
|
64
|
-
WorkerRegisterRequest(
|
|
65
|
-
workerName=req.worker_name,
|
|
66
|
-
actions=req.actions,
|
|
67
|
-
services=req.services,
|
|
68
|
-
maxRuns=req.max_runs,
|
|
69
|
-
labels=req.labels,
|
|
70
|
-
),
|
|
71
|
-
timeout=DEFAULT_REGISTER_TIMEOUT,
|
|
72
|
-
metadata=get_metadata(self.token),
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
return ActionListener(self.config, response.workerId)
|
|
76
|
-
|
|
77
|
-
async def send_step_action_event(
|
|
78
|
-
self, action: Action, event_type: StepActionEventType, payload: str
|
|
79
|
-
) -> Any:
|
|
80
|
-
try:
|
|
81
|
-
return await self._try_send_step_action_event(action, event_type, payload)
|
|
82
|
-
except Exception as e:
|
|
83
|
-
# for step action events, send a failure event when we cannot send the completed event
|
|
84
|
-
if (
|
|
85
|
-
event_type == STEP_EVENT_TYPE_COMPLETED
|
|
86
|
-
or event_type == STEP_EVENT_TYPE_FAILED
|
|
87
|
-
):
|
|
88
|
-
await self._try_send_step_action_event(
|
|
89
|
-
action,
|
|
90
|
-
STEP_EVENT_TYPE_FAILED,
|
|
91
|
-
"Failed to send finished event: " + str(e),
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
@tenacity_retry
|
|
97
|
-
async def _try_send_step_action_event(
|
|
98
|
-
self, action: Action, event_type: StepActionEventType, payload: str
|
|
99
|
-
) -> Any:
|
|
100
|
-
eventTimestamp = Timestamp()
|
|
101
|
-
eventTimestamp.GetCurrentTime()
|
|
102
|
-
|
|
103
|
-
event = StepActionEvent(
|
|
104
|
-
workerId=action.worker_id,
|
|
105
|
-
jobId=action.job_id,
|
|
106
|
-
jobRunId=action.job_run_id,
|
|
107
|
-
stepId=action.step_id,
|
|
108
|
-
stepRunId=action.step_run_id,
|
|
109
|
-
actionId=action.action_id,
|
|
110
|
-
eventTimestamp=eventTimestamp,
|
|
111
|
-
eventType=event_type,
|
|
112
|
-
eventPayload=payload,
|
|
113
|
-
retryCount=action.retry_count,
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
## TODO: What does this return?
|
|
117
|
-
return await self.aio_client.SendStepActionEvent(
|
|
118
|
-
event,
|
|
119
|
-
metadata=get_metadata(self.token),
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
async def send_group_key_action_event(
|
|
123
|
-
self, action: Action, event_type: GroupKeyActionEventType, payload: str
|
|
124
|
-
) -> Any:
|
|
125
|
-
eventTimestamp = Timestamp()
|
|
126
|
-
eventTimestamp.GetCurrentTime()
|
|
127
|
-
|
|
128
|
-
event = GroupKeyActionEvent(
|
|
129
|
-
workerId=action.worker_id,
|
|
130
|
-
workflowRunId=action.workflow_run_id,
|
|
131
|
-
getGroupKeyRunId=action.get_group_key_run_id,
|
|
132
|
-
actionId=action.action_id,
|
|
133
|
-
eventTimestamp=eventTimestamp,
|
|
134
|
-
eventType=event_type,
|
|
135
|
-
eventPayload=payload,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
## TODO: What does this return?
|
|
139
|
-
return await self.aio_client.SendGroupKeyActionEvent(
|
|
140
|
-
event,
|
|
141
|
-
metadata=get_metadata(self.token),
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
def put_overrides_data(self, data: OverridesData) -> ActionEventResponse:
|
|
145
|
-
return cast(
|
|
146
|
-
ActionEventResponse,
|
|
147
|
-
self.client.PutOverridesData(
|
|
148
|
-
data,
|
|
149
|
-
metadata=get_metadata(self.token),
|
|
150
|
-
),
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
def release_slot(self, step_run_id: str) -> None:
|
|
154
|
-
self.client.ReleaseSlot(
|
|
155
|
-
ReleaseSlotRequest(stepRunId=step_run_id),
|
|
156
|
-
timeout=DEFAULT_REGISTER_TIMEOUT,
|
|
157
|
-
metadata=get_metadata(self.token),
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
def refresh_timeout(self, step_run_id: str, increment_by: str) -> None:
|
|
161
|
-
self.client.RefreshTimeout(
|
|
162
|
-
RefreshTimeoutRequest(
|
|
163
|
-
stepRunId=step_run_id,
|
|
164
|
-
incrementTimeoutBy=increment_by,
|
|
165
|
-
),
|
|
166
|
-
timeout=DEFAULT_REGISTER_TIMEOUT,
|
|
167
|
-
metadata=get_metadata(self.token),
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
def upsert_worker_labels(
|
|
171
|
-
self, worker_id: str | None, labels: dict[str, str | int]
|
|
172
|
-
) -> None:
|
|
173
|
-
worker_labels = {}
|
|
174
|
-
|
|
175
|
-
for key, value in labels.items():
|
|
176
|
-
if isinstance(value, int):
|
|
177
|
-
worker_labels[key] = WorkerLabels(intValue=value)
|
|
178
|
-
else:
|
|
179
|
-
worker_labels[key] = WorkerLabels(strValue=str(value))
|
|
180
|
-
|
|
181
|
-
self.client.UpsertWorkerLabels(
|
|
182
|
-
UpsertWorkerLabelsRequest(workerId=worker_id, labels=worker_labels),
|
|
183
|
-
timeout=DEFAULT_REGISTER_TIMEOUT,
|
|
184
|
-
metadata=get_metadata(self.token),
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
async def async_upsert_worker_labels(
|
|
188
|
-
self,
|
|
189
|
-
worker_id: str | None,
|
|
190
|
-
labels: dict[str, str | int],
|
|
191
|
-
) -> None:
|
|
192
|
-
worker_labels = {}
|
|
193
|
-
|
|
194
|
-
for key, value in labels.items():
|
|
195
|
-
if isinstance(value, int):
|
|
196
|
-
worker_labels[key] = WorkerLabels(intValue=value)
|
|
197
|
-
else:
|
|
198
|
-
worker_labels[key] = WorkerLabels(strValue=str(value))
|
|
199
|
-
|
|
200
|
-
await self.aio_client.UpsertWorkerLabels(
|
|
201
|
-
UpsertWorkerLabelsRequest(workerId=worker_id, labels=worker_labels),
|
|
202
|
-
timeout=DEFAULT_REGISTER_TIMEOUT,
|
|
203
|
-
metadata=get_metadata(self.token),
|
|
204
|
-
)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ThreadSafeEvent(asyncio.Event):
|
|
6
|
-
"""
|
|
7
|
-
ThreadSafeEvent is a subclass of asyncio.Event that allows for thread-safe setting and clearing of the event.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
def __init__(self, *args, **kwargs):
|
|
11
|
-
super().__init__(*args, **kwargs)
|
|
12
|
-
if self._loop is None:
|
|
13
|
-
self._loop = asyncio.get_event_loop()
|
|
14
|
-
|
|
15
|
-
def set(self):
|
|
16
|
-
if not self._loop.is_closed():
|
|
17
|
-
self._loop.call_soon_threadsafe(super().set)
|
|
18
|
-
|
|
19
|
-
def clear(self):
|
|
20
|
-
self._loop.call_soon_threadsafe(super().clear)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
async def read_with_interrupt(listener: Any, interrupt: ThreadSafeEvent):
|
|
24
|
-
try:
|
|
25
|
-
result = await listener.read()
|
|
26
|
-
return result
|
|
27
|
-
finally:
|
|
28
|
-
interrupt.set()
|