hatchet-sdk 1.18.1__py3-none-any.whl → 1.19.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-1.18.1.dist-info → hatchet_sdk-1.19.0.dist-info}/METADATA +2 -3
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.19.0.dist-info}/RECORD +4 -225
- 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.19.0.dist-info}/WHEEL +0 -0
- {hatchet_sdk-1.18.1.dist-info → hatchet_sdk-1.19.0.dist-info}/entry_points.txt +0 -0
hatchet_sdk/v0/worker/worker.py
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import multiprocessing
|
|
3
|
-
import multiprocessing.context
|
|
4
|
-
import os
|
|
5
|
-
import signal
|
|
6
|
-
import sys
|
|
7
|
-
from concurrent.futures import Future
|
|
8
|
-
from dataclasses import dataclass, field
|
|
9
|
-
from enum import Enum
|
|
10
|
-
from multiprocessing import Queue
|
|
11
|
-
from multiprocessing.process import BaseProcess
|
|
12
|
-
from types import FrameType
|
|
13
|
-
from typing import Any, Callable, TypeVar, get_type_hints
|
|
14
|
-
|
|
15
|
-
from aiohttp import web
|
|
16
|
-
from aiohttp.web_request import Request
|
|
17
|
-
from aiohttp.web_response import Response
|
|
18
|
-
from prometheus_client import CONTENT_TYPE_LATEST, Gauge, generate_latest
|
|
19
|
-
|
|
20
|
-
from hatchet_sdk.contracts.workflows_pb2 import CreateWorkflowVersionOpts
|
|
21
|
-
from hatchet_sdk.logger import logger
|
|
22
|
-
from hatchet_sdk.v0 import Context
|
|
23
|
-
from hatchet_sdk.v0.client import Client, new_client_raw
|
|
24
|
-
from hatchet_sdk.v0.loader import ClientConfig
|
|
25
|
-
from hatchet_sdk.v0.utils.types import WorkflowValidator
|
|
26
|
-
from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
|
|
27
|
-
from hatchet_sdk.v0.v2.callable import HatchetCallable
|
|
28
|
-
from hatchet_sdk.v0.v2.concurrency import ConcurrencyFunction
|
|
29
|
-
from hatchet_sdk.v0.worker.action_listener_process import worker_action_listener_process
|
|
30
|
-
from hatchet_sdk.v0.worker.runner.run_loop_manager import WorkerActionRunLoopManager
|
|
31
|
-
from hatchet_sdk.v0.workflow import WorkflowInterface
|
|
32
|
-
|
|
33
|
-
T = TypeVar("T")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class WorkerStatus(Enum):
|
|
37
|
-
INITIALIZED = 1
|
|
38
|
-
STARTING = 2
|
|
39
|
-
HEALTHY = 3
|
|
40
|
-
UNHEALTHY = 4
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@dataclass
|
|
44
|
-
class WorkerStartOptions:
|
|
45
|
-
loop: asyncio.AbstractEventLoop | None = field(default=None)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
TWorkflow = TypeVar("TWorkflow", bound=object)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Worker:
|
|
52
|
-
def __init__(
|
|
53
|
-
self,
|
|
54
|
-
name: str,
|
|
55
|
-
config: ClientConfig = ClientConfig(),
|
|
56
|
-
max_runs: int | None = None,
|
|
57
|
-
labels: dict[str, str | int] = {},
|
|
58
|
-
debug: bool = False,
|
|
59
|
-
owned_loop: bool = True,
|
|
60
|
-
handle_kill: bool = True,
|
|
61
|
-
) -> None:
|
|
62
|
-
self.name = name
|
|
63
|
-
self.config = config
|
|
64
|
-
self.max_runs = max_runs
|
|
65
|
-
self.debug = debug
|
|
66
|
-
self.labels = labels
|
|
67
|
-
self.handle_kill = handle_kill
|
|
68
|
-
self.owned_loop = owned_loop
|
|
69
|
-
|
|
70
|
-
self.client: Client
|
|
71
|
-
|
|
72
|
-
self.action_registry: dict[str, Callable[[Context], Any]] = {}
|
|
73
|
-
self.validator_registry: dict[str, WorkflowValidator] = {}
|
|
74
|
-
|
|
75
|
-
self.killing: bool = False
|
|
76
|
-
self._status: WorkerStatus
|
|
77
|
-
|
|
78
|
-
self.action_listener_process: BaseProcess
|
|
79
|
-
self.action_listener_health_check: asyncio.Task[Any]
|
|
80
|
-
self.action_runner: WorkerActionRunLoopManager
|
|
81
|
-
|
|
82
|
-
self.ctx = multiprocessing.get_context("spawn")
|
|
83
|
-
|
|
84
|
-
self.action_queue: "Queue[Any]" = self.ctx.Queue()
|
|
85
|
-
self.event_queue: "Queue[Any]" = self.ctx.Queue()
|
|
86
|
-
|
|
87
|
-
self.loop: asyncio.AbstractEventLoop
|
|
88
|
-
|
|
89
|
-
self.client = new_client_raw(self.config, self.debug)
|
|
90
|
-
self.name = self.client.config.namespace + self.name
|
|
91
|
-
|
|
92
|
-
self._setup_signal_handlers()
|
|
93
|
-
|
|
94
|
-
self.worker_status_gauge = Gauge(
|
|
95
|
-
"hatchet_worker_status", "Current status of the Hatchet worker"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
def register_function(self, action: str, func: Callable[[Context], Any]) -> None:
|
|
99
|
-
self.action_registry[action] = func
|
|
100
|
-
|
|
101
|
-
def register_workflow_from_opts(
|
|
102
|
-
self, name: str, opts: CreateWorkflowVersionOpts
|
|
103
|
-
) -> None:
|
|
104
|
-
try:
|
|
105
|
-
self.client.admin.put_workflow(opts.name, opts)
|
|
106
|
-
except Exception as e:
|
|
107
|
-
logger.error(f"failed to register workflow: {opts.name}")
|
|
108
|
-
logger.error(e)
|
|
109
|
-
sys.exit(1)
|
|
110
|
-
|
|
111
|
-
def register_workflow(self, workflow: TWorkflow) -> None:
|
|
112
|
-
## Hack for typing
|
|
113
|
-
assert isinstance(workflow, WorkflowInterface)
|
|
114
|
-
|
|
115
|
-
namespace = self.client.config.namespace
|
|
116
|
-
|
|
117
|
-
try:
|
|
118
|
-
self.client.admin.put_workflow(
|
|
119
|
-
workflow.get_name(namespace), workflow.get_create_opts(namespace)
|
|
120
|
-
)
|
|
121
|
-
except Exception as e:
|
|
122
|
-
logger.error(f"failed to register workflow: {workflow.get_name(namespace)}")
|
|
123
|
-
logger.error(e)
|
|
124
|
-
sys.exit(1)
|
|
125
|
-
|
|
126
|
-
def create_action_function(
|
|
127
|
-
action_func: Callable[..., T]
|
|
128
|
-
) -> Callable[[Context], T]:
|
|
129
|
-
def action_function(context: Context) -> T:
|
|
130
|
-
return action_func(workflow, context)
|
|
131
|
-
|
|
132
|
-
if asyncio.iscoroutinefunction(action_func):
|
|
133
|
-
setattr(action_function, "is_coroutine", True)
|
|
134
|
-
else:
|
|
135
|
-
setattr(action_function, "is_coroutine", False)
|
|
136
|
-
|
|
137
|
-
return action_function
|
|
138
|
-
|
|
139
|
-
for action_name, action_func in workflow.get_actions(namespace):
|
|
140
|
-
self.action_registry[action_name] = create_action_function(action_func)
|
|
141
|
-
return_type = get_type_hints(action_func).get("return")
|
|
142
|
-
|
|
143
|
-
self.validator_registry[action_name] = WorkflowValidator(
|
|
144
|
-
workflow_input=workflow.input_validator,
|
|
145
|
-
step_output=return_type if is_basemodel_subclass(return_type) else None,
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
def status(self) -> WorkerStatus:
|
|
149
|
-
return self._status
|
|
150
|
-
|
|
151
|
-
def setup_loop(self, loop: asyncio.AbstractEventLoop | None = None) -> bool:
|
|
152
|
-
try:
|
|
153
|
-
loop = loop or asyncio.get_running_loop()
|
|
154
|
-
self.loop = loop
|
|
155
|
-
created_loop = False
|
|
156
|
-
logger.debug("using existing event loop")
|
|
157
|
-
return created_loop
|
|
158
|
-
except RuntimeError:
|
|
159
|
-
self.loop = asyncio.new_event_loop()
|
|
160
|
-
logger.debug("creating new event loop")
|
|
161
|
-
asyncio.set_event_loop(self.loop)
|
|
162
|
-
created_loop = True
|
|
163
|
-
return created_loop
|
|
164
|
-
|
|
165
|
-
async def health_check_handler(self, request: Request) -> Response:
|
|
166
|
-
status = self.status()
|
|
167
|
-
|
|
168
|
-
return web.json_response({"status": status.name})
|
|
169
|
-
|
|
170
|
-
async def metrics_handler(self, request: Request) -> Response:
|
|
171
|
-
self.worker_status_gauge.set(1 if self.status() == WorkerStatus.HEALTHY else 0)
|
|
172
|
-
|
|
173
|
-
return web.Response(body=generate_latest(), content_type="text/plain")
|
|
174
|
-
|
|
175
|
-
async def start_health_server(self) -> None:
|
|
176
|
-
port = self.config.worker_healthcheck_port or 8001
|
|
177
|
-
|
|
178
|
-
app = web.Application()
|
|
179
|
-
app.add_routes(
|
|
180
|
-
[
|
|
181
|
-
web.get("/health", self.health_check_handler),
|
|
182
|
-
web.get("/metrics", self.metrics_handler),
|
|
183
|
-
]
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
runner = web.AppRunner(app)
|
|
187
|
-
|
|
188
|
-
try:
|
|
189
|
-
await runner.setup()
|
|
190
|
-
await web.TCPSite(runner, "0.0.0.0", port).start()
|
|
191
|
-
except Exception as e:
|
|
192
|
-
logger.error("failed to start healthcheck server")
|
|
193
|
-
logger.error(str(e))
|
|
194
|
-
return
|
|
195
|
-
|
|
196
|
-
logger.info(f"healthcheck server running on port {port}")
|
|
197
|
-
|
|
198
|
-
def start(
|
|
199
|
-
self, options: WorkerStartOptions = WorkerStartOptions()
|
|
200
|
-
) -> Future[asyncio.Task[None]]:
|
|
201
|
-
self.owned_loop = self.setup_loop(options.loop)
|
|
202
|
-
|
|
203
|
-
f = asyncio.run_coroutine_threadsafe(
|
|
204
|
-
self._async_start(options, _from_start=True), self.loop
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
# start the loop and wait until its closed
|
|
208
|
-
if self.owned_loop:
|
|
209
|
-
self.loop.run_forever()
|
|
210
|
-
|
|
211
|
-
if self.handle_kill:
|
|
212
|
-
sys.exit(0)
|
|
213
|
-
|
|
214
|
-
return f
|
|
215
|
-
|
|
216
|
-
## Start methods
|
|
217
|
-
async def _async_start(
|
|
218
|
-
self,
|
|
219
|
-
options: WorkerStartOptions = WorkerStartOptions(),
|
|
220
|
-
_from_start: bool = False,
|
|
221
|
-
) -> asyncio.Task[None]:
|
|
222
|
-
main_pid = os.getpid()
|
|
223
|
-
logger.info("------------------------------------------")
|
|
224
|
-
logger.info("STARTING HATCHET...")
|
|
225
|
-
logger.debug(f"worker runtime starting on PID: {main_pid}")
|
|
226
|
-
|
|
227
|
-
self._status = WorkerStatus.STARTING
|
|
228
|
-
|
|
229
|
-
if len(self.action_registry.keys()) == 0:
|
|
230
|
-
raise ValueError(
|
|
231
|
-
"no actions registered, register workflows or actions before starting worker"
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
# non blocking setup
|
|
235
|
-
if not _from_start:
|
|
236
|
-
self.setup_loop(options.loop)
|
|
237
|
-
|
|
238
|
-
if self.config.worker_healthcheck_enabled:
|
|
239
|
-
await self.start_health_server()
|
|
240
|
-
|
|
241
|
-
self.action_listener_process = self._start_listener()
|
|
242
|
-
|
|
243
|
-
self.action_runner = self._run_action_runner()
|
|
244
|
-
|
|
245
|
-
self.action_listener_health_check = self.loop.create_task(
|
|
246
|
-
self._check_listener_health()
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
return await self.action_listener_health_check
|
|
250
|
-
|
|
251
|
-
def _run_action_runner(self) -> WorkerActionRunLoopManager:
|
|
252
|
-
# Retrieve the shared queue
|
|
253
|
-
return WorkerActionRunLoopManager(
|
|
254
|
-
self.name,
|
|
255
|
-
self.action_registry,
|
|
256
|
-
self.validator_registry,
|
|
257
|
-
self.max_runs,
|
|
258
|
-
self.config,
|
|
259
|
-
self.action_queue,
|
|
260
|
-
self.event_queue,
|
|
261
|
-
self.loop,
|
|
262
|
-
self.handle_kill,
|
|
263
|
-
self.client.debug,
|
|
264
|
-
self.labels,
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
def _start_listener(self) -> multiprocessing.context.SpawnProcess:
|
|
268
|
-
action_list = [str(key) for key in self.action_registry.keys()]
|
|
269
|
-
|
|
270
|
-
try:
|
|
271
|
-
process = self.ctx.Process(
|
|
272
|
-
target=worker_action_listener_process,
|
|
273
|
-
args=(
|
|
274
|
-
self.name,
|
|
275
|
-
action_list,
|
|
276
|
-
self.max_runs,
|
|
277
|
-
self.config,
|
|
278
|
-
self.action_queue,
|
|
279
|
-
self.event_queue,
|
|
280
|
-
self.handle_kill,
|
|
281
|
-
self.client.debug,
|
|
282
|
-
self.labels,
|
|
283
|
-
),
|
|
284
|
-
)
|
|
285
|
-
process.start()
|
|
286
|
-
logger.debug(f"action listener starting on PID: {process.pid}")
|
|
287
|
-
|
|
288
|
-
return process
|
|
289
|
-
except Exception as e:
|
|
290
|
-
logger.error(f"failed to start action listener: {e}")
|
|
291
|
-
sys.exit(1)
|
|
292
|
-
|
|
293
|
-
async def _check_listener_health(self) -> None:
|
|
294
|
-
logger.debug("starting action listener health check...")
|
|
295
|
-
try:
|
|
296
|
-
while not self.killing:
|
|
297
|
-
if (
|
|
298
|
-
self.action_listener_process is None
|
|
299
|
-
or not self.action_listener_process.is_alive()
|
|
300
|
-
):
|
|
301
|
-
logger.debug("child action listener process killed...")
|
|
302
|
-
self._status = WorkerStatus.UNHEALTHY
|
|
303
|
-
if not self.killing:
|
|
304
|
-
self.loop.create_task(self.exit_gracefully())
|
|
305
|
-
break
|
|
306
|
-
else:
|
|
307
|
-
self._status = WorkerStatus.HEALTHY
|
|
308
|
-
await asyncio.sleep(1)
|
|
309
|
-
except Exception as e:
|
|
310
|
-
logger.error(f"error checking listener health: {e}")
|
|
311
|
-
|
|
312
|
-
## Cleanup methods
|
|
313
|
-
def _setup_signal_handlers(self) -> None:
|
|
314
|
-
signal.signal(signal.SIGTERM, self._handle_exit_signal)
|
|
315
|
-
signal.signal(signal.SIGINT, self._handle_exit_signal)
|
|
316
|
-
signal.signal(signal.SIGQUIT, self._handle_force_quit_signal)
|
|
317
|
-
|
|
318
|
-
def _handle_exit_signal(self, signum: int, frame: FrameType | None) -> None:
|
|
319
|
-
sig_name = "SIGTERM" if signum == signal.SIGTERM else "SIGINT"
|
|
320
|
-
logger.info(f"received signal {sig_name}...")
|
|
321
|
-
self.loop.create_task(self.exit_gracefully())
|
|
322
|
-
|
|
323
|
-
def _handle_force_quit_signal(self, signum: int, frame: FrameType | None) -> None:
|
|
324
|
-
logger.info("received SIGQUIT...")
|
|
325
|
-
self.exit_forcefully()
|
|
326
|
-
|
|
327
|
-
async def close(self) -> None:
|
|
328
|
-
logger.info(f"closing worker '{self.name}'...")
|
|
329
|
-
self.killing = True
|
|
330
|
-
# self.action_queue.close()
|
|
331
|
-
# self.event_queue.close()
|
|
332
|
-
|
|
333
|
-
if self.action_runner is not None:
|
|
334
|
-
self.action_runner.cleanup()
|
|
335
|
-
|
|
336
|
-
await self.action_listener_health_check
|
|
337
|
-
|
|
338
|
-
async def exit_gracefully(self) -> None:
|
|
339
|
-
logger.debug(f"gracefully stopping worker: {self.name}")
|
|
340
|
-
|
|
341
|
-
if self.killing:
|
|
342
|
-
return self.exit_forcefully()
|
|
343
|
-
|
|
344
|
-
self.killing = True
|
|
345
|
-
|
|
346
|
-
await self.action_runner.wait_for_tasks()
|
|
347
|
-
|
|
348
|
-
await self.action_runner.exit_gracefully()
|
|
349
|
-
|
|
350
|
-
if self.action_listener_process and self.action_listener_process.is_alive():
|
|
351
|
-
self.action_listener_process.kill()
|
|
352
|
-
|
|
353
|
-
await self.close()
|
|
354
|
-
if self.loop and self.owned_loop:
|
|
355
|
-
self.loop.stop()
|
|
356
|
-
|
|
357
|
-
logger.info("👋")
|
|
358
|
-
|
|
359
|
-
def exit_forcefully(self) -> None:
|
|
360
|
-
self.killing = True
|
|
361
|
-
|
|
362
|
-
logger.debug(f"forcefully stopping worker: {self.name}")
|
|
363
|
-
|
|
364
|
-
self.close()
|
|
365
|
-
|
|
366
|
-
if self.action_listener_process:
|
|
367
|
-
self.action_listener_process.kill() # Forcefully kill the process
|
|
368
|
-
|
|
369
|
-
logger.info("👋")
|
|
370
|
-
sys.exit(
|
|
371
|
-
1
|
|
372
|
-
) # Exit immediately TODO - should we exit with 1 here, there may be other workers to cleanup
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
def register_on_worker(callable: HatchetCallable[T], worker: Worker) -> None:
|
|
376
|
-
worker.register_function(callable.get_action_name(), callable)
|
|
377
|
-
|
|
378
|
-
if callable.function_on_failure is not None:
|
|
379
|
-
worker.register_function(
|
|
380
|
-
callable.function_on_failure.get_action_name(), callable.function_on_failure
|
|
381
|
-
)
|
|
382
|
-
|
|
383
|
-
if callable.function_concurrency is not None:
|
|
384
|
-
worker.register_function(
|
|
385
|
-
callable.function_concurrency.get_action_name(),
|
|
386
|
-
callable.function_concurrency,
|
|
387
|
-
)
|
|
388
|
-
|
|
389
|
-
opts = callable.to_workflow_opts()
|
|
390
|
-
|
|
391
|
-
worker.register_workflow_from_opts(opts.name, opts)
|
hatchet_sdk/v0/workflow.py
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import functools
|
|
2
|
-
from typing import (
|
|
3
|
-
Any,
|
|
4
|
-
Callable,
|
|
5
|
-
Protocol,
|
|
6
|
-
Type,
|
|
7
|
-
TypeVar,
|
|
8
|
-
Union,
|
|
9
|
-
cast,
|
|
10
|
-
get_type_hints,
|
|
11
|
-
runtime_checkable,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
from pydantic import BaseModel
|
|
15
|
-
|
|
16
|
-
from hatchet_sdk.contracts.workflows_pb2 import (
|
|
17
|
-
CreateWorkflowJobOpts,
|
|
18
|
-
CreateWorkflowStepOpts,
|
|
19
|
-
CreateWorkflowVersionOpts,
|
|
20
|
-
StickyStrategy,
|
|
21
|
-
WorkflowConcurrencyOpts,
|
|
22
|
-
WorkflowKind,
|
|
23
|
-
)
|
|
24
|
-
from hatchet_sdk.logger import logger
|
|
25
|
-
from hatchet_sdk.v0 import ConcurrencyLimitStrategy
|
|
26
|
-
from hatchet_sdk.v0.utils.typing import is_basemodel_subclass
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class WorkflowStepProtocol(Protocol):
|
|
30
|
-
def __call__(self, *args: Any, **kwargs: Any) -> Any: ...
|
|
31
|
-
|
|
32
|
-
__name__: str
|
|
33
|
-
|
|
34
|
-
_step_name: str
|
|
35
|
-
_step_timeout: str | None
|
|
36
|
-
_step_parents: list[str]
|
|
37
|
-
_step_retries: int | None
|
|
38
|
-
_step_rate_limits: list[str] | None
|
|
39
|
-
_step_desired_worker_labels: dict[str, str]
|
|
40
|
-
_step_backoff_factor: float | None
|
|
41
|
-
_step_backoff_max_seconds: int | None
|
|
42
|
-
|
|
43
|
-
_concurrency_fn_name: str
|
|
44
|
-
_concurrency_max_runs: int | None
|
|
45
|
-
_concurrency_limit_strategy: str | None
|
|
46
|
-
|
|
47
|
-
_on_failure_step_name: str
|
|
48
|
-
_on_failure_step_timeout: str | None
|
|
49
|
-
_on_failure_step_retries: int
|
|
50
|
-
_on_failure_step_rate_limits: list[str] | None
|
|
51
|
-
_on_failure_step_backoff_factor: float | None
|
|
52
|
-
_on_failure_step_backoff_max_seconds: int | None
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
StepsType = list[tuple[str, WorkflowStepProtocol]]
|
|
56
|
-
|
|
57
|
-
T = TypeVar("T")
|
|
58
|
-
TW = TypeVar("TW", bound="WorkflowInterface")
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class ConcurrencyExpression:
|
|
62
|
-
"""
|
|
63
|
-
Defines concurrency limits for a workflow using a CEL expression.
|
|
64
|
-
|
|
65
|
-
Args:
|
|
66
|
-
expression (str): CEL expression to determine concurrency grouping. (i.e. "input.user_id")
|
|
67
|
-
max_runs (int): Maximum number of concurrent workflow runs.
|
|
68
|
-
limit_strategy (ConcurrencyLimitStrategy): Strategy for handling limit violations.
|
|
69
|
-
|
|
70
|
-
Example:
|
|
71
|
-
ConcurrencyExpression("input.user_id", 5, ConcurrencyLimitStrategy.CANCEL_IN_PROGRESS)
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
def __init__(
|
|
75
|
-
self, expression: str, max_runs: int, limit_strategy: ConcurrencyLimitStrategy
|
|
76
|
-
):
|
|
77
|
-
self.expression = expression
|
|
78
|
-
self.max_runs = max_runs
|
|
79
|
-
self.limit_strategy = limit_strategy
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@runtime_checkable
|
|
83
|
-
class WorkflowInterface(Protocol):
|
|
84
|
-
def get_name(self, namespace: str) -> str: ...
|
|
85
|
-
|
|
86
|
-
def get_actions(self, namespace: str) -> list[tuple[str, Callable[..., Any]]]: ...
|
|
87
|
-
|
|
88
|
-
def get_create_opts(self, namespace: str) -> Any: ...
|
|
89
|
-
|
|
90
|
-
on_events: list[str] | None
|
|
91
|
-
on_crons: list[str] | None
|
|
92
|
-
name: str
|
|
93
|
-
version: str
|
|
94
|
-
timeout: str
|
|
95
|
-
schedule_timeout: str
|
|
96
|
-
sticky: Union[StickyStrategy.Value, None] # type: ignore[name-defined]
|
|
97
|
-
default_priority: int | None
|
|
98
|
-
concurrency_expression: ConcurrencyExpression | None
|
|
99
|
-
input_validator: Type[BaseModel] | None
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class WorkflowMeta(type):
|
|
103
|
-
def __new__(
|
|
104
|
-
cls: Type["WorkflowMeta"],
|
|
105
|
-
name: str,
|
|
106
|
-
bases: tuple[type, ...],
|
|
107
|
-
attrs: dict[str, Any],
|
|
108
|
-
) -> "WorkflowMeta":
|
|
109
|
-
def _create_steps_actions_list(name: str) -> StepsType:
|
|
110
|
-
return [
|
|
111
|
-
(getattr(func, name), attrs.pop(func_name))
|
|
112
|
-
for func_name, func in list(attrs.items())
|
|
113
|
-
if hasattr(func, name)
|
|
114
|
-
]
|
|
115
|
-
|
|
116
|
-
concurrencyActions = _create_steps_actions_list("_concurrency_fn_name")
|
|
117
|
-
steps = _create_steps_actions_list("_step_name")
|
|
118
|
-
|
|
119
|
-
onFailureSteps = _create_steps_actions_list("_on_failure_step_name")
|
|
120
|
-
|
|
121
|
-
# Define __init__ and get_step_order methods
|
|
122
|
-
original_init = attrs.get("__init__") # Get the original __init__ if it exists
|
|
123
|
-
|
|
124
|
-
def __init__(self: TW, *args: Any, **kwargs: Any) -> None:
|
|
125
|
-
if original_init:
|
|
126
|
-
original_init(self, *args, **kwargs) # Call original __init__
|
|
127
|
-
|
|
128
|
-
def get_service_name(namespace: str) -> str:
|
|
129
|
-
return f"{namespace}{name.lower()}"
|
|
130
|
-
|
|
131
|
-
@functools.cache
|
|
132
|
-
def get_actions(self: TW, namespace: str) -> StepsType:
|
|
133
|
-
serviceName = get_service_name(namespace)
|
|
134
|
-
|
|
135
|
-
func_actions = [
|
|
136
|
-
(serviceName + ":" + func_name, func) for func_name, func in steps
|
|
137
|
-
]
|
|
138
|
-
concurrency_actions = [
|
|
139
|
-
(serviceName + ":" + func_name, func)
|
|
140
|
-
for func_name, func in concurrencyActions
|
|
141
|
-
]
|
|
142
|
-
onFailure_actions = [
|
|
143
|
-
(serviceName + ":" + func_name, func)
|
|
144
|
-
for func_name, func in onFailureSteps
|
|
145
|
-
]
|
|
146
|
-
|
|
147
|
-
return func_actions + concurrency_actions + onFailure_actions
|
|
148
|
-
|
|
149
|
-
# Add these methods and steps to class attributes
|
|
150
|
-
attrs["__init__"] = __init__
|
|
151
|
-
attrs["get_actions"] = get_actions
|
|
152
|
-
|
|
153
|
-
for step_name, step_func in steps:
|
|
154
|
-
attrs[step_name] = step_func
|
|
155
|
-
|
|
156
|
-
def get_name(self: TW, namespace: str) -> str:
|
|
157
|
-
return namespace + cast(str, attrs["name"])
|
|
158
|
-
|
|
159
|
-
attrs["get_name"] = get_name
|
|
160
|
-
|
|
161
|
-
cron_triggers = attrs["on_crons"]
|
|
162
|
-
version = attrs["version"]
|
|
163
|
-
schedule_timeout = attrs["schedule_timeout"]
|
|
164
|
-
sticky = attrs["sticky"]
|
|
165
|
-
default_priority = attrs["default_priority"]
|
|
166
|
-
|
|
167
|
-
@functools.cache
|
|
168
|
-
def get_create_opts(self: TW, namespace: str) -> CreateWorkflowVersionOpts:
|
|
169
|
-
serviceName = get_service_name(namespace)
|
|
170
|
-
name = self.get_name(namespace)
|
|
171
|
-
event_triggers = [namespace + event for event in attrs["on_events"]]
|
|
172
|
-
createStepOpts: list[CreateWorkflowStepOpts] = [
|
|
173
|
-
CreateWorkflowStepOpts(
|
|
174
|
-
readable_id=step_name,
|
|
175
|
-
action=serviceName + ":" + step_name,
|
|
176
|
-
timeout=func._step_timeout or "60s",
|
|
177
|
-
inputs="{}",
|
|
178
|
-
parents=[x for x in func._step_parents],
|
|
179
|
-
retries=func._step_retries,
|
|
180
|
-
rate_limits=func._step_rate_limits, # type: ignore[arg-type]
|
|
181
|
-
worker_labels=func._step_desired_worker_labels, # type: ignore[arg-type]
|
|
182
|
-
backoff_factor=func._step_backoff_factor,
|
|
183
|
-
backoff_max_seconds=func._step_backoff_max_seconds,
|
|
184
|
-
)
|
|
185
|
-
for step_name, func in steps
|
|
186
|
-
]
|
|
187
|
-
|
|
188
|
-
concurrency: WorkflowConcurrencyOpts | None = None
|
|
189
|
-
|
|
190
|
-
if len(concurrencyActions) > 0:
|
|
191
|
-
action = concurrencyActions[0]
|
|
192
|
-
|
|
193
|
-
concurrency = WorkflowConcurrencyOpts(
|
|
194
|
-
action=serviceName + ":" + action[0],
|
|
195
|
-
max_runs=action[1]._concurrency_max_runs,
|
|
196
|
-
limit_strategy=action[1]._concurrency_limit_strategy,
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
if self.concurrency_expression:
|
|
200
|
-
concurrency = WorkflowConcurrencyOpts(
|
|
201
|
-
expression=self.concurrency_expression.expression,
|
|
202
|
-
max_runs=self.concurrency_expression.max_runs,
|
|
203
|
-
limit_strategy=self.concurrency_expression.limit_strategy,
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
if len(concurrencyActions) > 0 and self.concurrency_expression:
|
|
207
|
-
raise ValueError(
|
|
208
|
-
"Error: Both concurrencyActions and concurrency_expression are defined. Please use only one concurrency configuration method."
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
on_failure_job: CreateWorkflowJobOpts | None = None
|
|
212
|
-
|
|
213
|
-
if len(onFailureSteps) > 0:
|
|
214
|
-
func_name, func = onFailureSteps[0]
|
|
215
|
-
on_failure_job = CreateWorkflowJobOpts(
|
|
216
|
-
name=name + "-on-failure",
|
|
217
|
-
steps=[
|
|
218
|
-
CreateWorkflowStepOpts(
|
|
219
|
-
readable_id=func_name,
|
|
220
|
-
action=serviceName + ":" + func_name,
|
|
221
|
-
timeout=func._on_failure_step_timeout or "60s",
|
|
222
|
-
inputs="{}",
|
|
223
|
-
parents=[],
|
|
224
|
-
retries=func._on_failure_step_retries,
|
|
225
|
-
rate_limits=func._on_failure_step_rate_limits, # type: ignore[arg-type]
|
|
226
|
-
backoff_factor=func._on_failure_step_backoff_factor,
|
|
227
|
-
backoff_max_seconds=func._on_failure_step_backoff_max_seconds,
|
|
228
|
-
)
|
|
229
|
-
],
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
validated_priority = (
|
|
233
|
-
max(1, min(3, default_priority)) if default_priority else None
|
|
234
|
-
)
|
|
235
|
-
if validated_priority != default_priority:
|
|
236
|
-
logger.warning(
|
|
237
|
-
"Warning: Default Priority Must be between 1 and 3 -- inclusively. Adjusted to be within the range."
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
return CreateWorkflowVersionOpts(
|
|
241
|
-
name=name,
|
|
242
|
-
kind=WorkflowKind.DAG,
|
|
243
|
-
version=version,
|
|
244
|
-
event_triggers=event_triggers,
|
|
245
|
-
cron_triggers=cron_triggers,
|
|
246
|
-
schedule_timeout=schedule_timeout,
|
|
247
|
-
sticky=sticky,
|
|
248
|
-
jobs=[
|
|
249
|
-
CreateWorkflowJobOpts(
|
|
250
|
-
name=name,
|
|
251
|
-
steps=createStepOpts,
|
|
252
|
-
)
|
|
253
|
-
],
|
|
254
|
-
on_failure_job=on_failure_job,
|
|
255
|
-
concurrency=concurrency,
|
|
256
|
-
default_priority=validated_priority,
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
attrs["get_create_opts"] = get_create_opts
|
|
260
|
-
|
|
261
|
-
return super(WorkflowMeta, cls).__new__(cls, name, bases, attrs)
|
hatchet_sdk/v0/workflow_run.py
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
from typing import Any, Coroutine, Generic, Optional, TypedDict, TypeVar
|
|
3
|
-
|
|
4
|
-
from hatchet_sdk.v0.clients.run_event_listener import (
|
|
5
|
-
RunEventListener,
|
|
6
|
-
RunEventListenerClient,
|
|
7
|
-
)
|
|
8
|
-
from hatchet_sdk.v0.clients.workflow_listener import PooledWorkflowRunListener
|
|
9
|
-
from hatchet_sdk.v0.utils.aio_utils import EventLoopThread, get_active_event_loop
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class WorkflowRunRef:
|
|
13
|
-
workflow_run_id: str
|
|
14
|
-
|
|
15
|
-
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
workflow_run_id: str,
|
|
18
|
-
workflow_listener: PooledWorkflowRunListener,
|
|
19
|
-
workflow_run_event_listener: RunEventListenerClient,
|
|
20
|
-
):
|
|
21
|
-
self.workflow_run_id = workflow_run_id
|
|
22
|
-
self.workflow_listener = workflow_listener
|
|
23
|
-
self.workflow_run_event_listener = workflow_run_event_listener
|
|
24
|
-
|
|
25
|
-
def __str__(self):
|
|
26
|
-
return self.workflow_run_id
|
|
27
|
-
|
|
28
|
-
def stream(self) -> RunEventListener:
|
|
29
|
-
return self.workflow_run_event_listener.stream(self.workflow_run_id)
|
|
30
|
-
|
|
31
|
-
def result(self) -> Coroutine:
|
|
32
|
-
return self.workflow_listener.result(self.workflow_run_id)
|
|
33
|
-
|
|
34
|
-
def sync_result(self) -> dict:
|
|
35
|
-
coro = self.workflow_listener.result(self.workflow_run_id)
|
|
36
|
-
loop = get_active_event_loop()
|
|
37
|
-
|
|
38
|
-
if loop is None:
|
|
39
|
-
loop = asyncio.new_event_loop()
|
|
40
|
-
asyncio.set_event_loop(loop)
|
|
41
|
-
try:
|
|
42
|
-
return loop.run_until_complete(coro)
|
|
43
|
-
finally:
|
|
44
|
-
asyncio.set_event_loop(None)
|
|
45
|
-
else:
|
|
46
|
-
return loop.run_until_complete(coro)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
T = TypeVar("T")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class RunRef(WorkflowRunRef, Generic[T]):
|
|
53
|
-
async def result(self) -> T:
|
|
54
|
-
res = await self.workflow_listener.result(self.workflow_run_id)
|
|
55
|
-
|
|
56
|
-
if len(res) == 1:
|
|
57
|
-
return list(res.values())[0]
|
|
58
|
-
|
|
59
|
-
return res
|