prefect-client 2.20.2__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prefect/__init__.py +74 -110
- prefect/_internal/compatibility/deprecated.py +6 -115
- prefect/_internal/compatibility/experimental.py +4 -79
- prefect/_internal/compatibility/migration.py +166 -0
- prefect/_internal/concurrency/__init__.py +2 -2
- prefect/_internal/concurrency/api.py +1 -35
- prefect/_internal/concurrency/calls.py +0 -6
- prefect/_internal/concurrency/cancellation.py +0 -3
- prefect/_internal/concurrency/event_loop.py +0 -20
- prefect/_internal/concurrency/inspection.py +3 -3
- prefect/_internal/concurrency/primitives.py +1 -0
- prefect/_internal/concurrency/services.py +23 -0
- prefect/_internal/concurrency/threads.py +35 -0
- prefect/_internal/concurrency/waiters.py +0 -28
- prefect/_internal/integrations.py +7 -0
- prefect/_internal/pydantic/__init__.py +0 -45
- prefect/_internal/pydantic/annotations/pendulum.py +2 -2
- prefect/_internal/pydantic/v1_schema.py +21 -22
- prefect/_internal/pydantic/v2_schema.py +0 -2
- prefect/_internal/pydantic/v2_validated_func.py +18 -23
- prefect/_internal/pytz.py +1 -1
- prefect/_internal/retries.py +61 -0
- prefect/_internal/schemas/bases.py +45 -177
- prefect/_internal/schemas/fields.py +1 -43
- prefect/_internal/schemas/validators.py +47 -233
- prefect/agent.py +3 -695
- prefect/artifacts.py +173 -14
- prefect/automations.py +39 -4
- prefect/blocks/abstract.py +1 -1
- prefect/blocks/core.py +423 -164
- prefect/blocks/fields.py +2 -57
- prefect/blocks/notifications.py +43 -28
- prefect/blocks/redis.py +168 -0
- prefect/blocks/system.py +67 -20
- prefect/blocks/webhook.py +2 -9
- prefect/cache_policies.py +239 -0
- prefect/client/__init__.py +4 -0
- prefect/client/base.py +33 -27
- prefect/client/cloud.py +65 -20
- prefect/client/collections.py +1 -1
- prefect/client/orchestration.py +667 -440
- prefect/client/schemas/actions.py +115 -100
- prefect/client/schemas/filters.py +46 -52
- prefect/client/schemas/objects.py +228 -178
- prefect/client/schemas/responses.py +18 -36
- prefect/client/schemas/schedules.py +55 -36
- prefect/client/schemas/sorting.py +2 -0
- prefect/client/subscriptions.py +8 -7
- prefect/client/types/flexible_schedule_list.py +11 -0
- prefect/client/utilities.py +9 -6
- prefect/concurrency/asyncio.py +60 -11
- prefect/concurrency/context.py +24 -0
- prefect/concurrency/events.py +2 -2
- prefect/concurrency/services.py +46 -16
- prefect/concurrency/sync.py +51 -7
- prefect/concurrency/v1/asyncio.py +143 -0
- prefect/concurrency/v1/context.py +27 -0
- prefect/concurrency/v1/events.py +61 -0
- prefect/concurrency/v1/services.py +116 -0
- prefect/concurrency/v1/sync.py +92 -0
- prefect/context.py +246 -149
- prefect/deployments/__init__.py +33 -18
- prefect/deployments/base.py +10 -15
- prefect/deployments/deployments.py +2 -1048
- prefect/deployments/flow_runs.py +178 -0
- prefect/deployments/runner.py +72 -173
- prefect/deployments/schedules.py +31 -25
- prefect/deployments/steps/__init__.py +0 -1
- prefect/deployments/steps/core.py +7 -0
- prefect/deployments/steps/pull.py +15 -21
- prefect/deployments/steps/utility.py +2 -1
- prefect/docker/__init__.py +20 -0
- prefect/docker/docker_image.py +82 -0
- prefect/engine.py +15 -2466
- prefect/events/actions.py +17 -23
- prefect/events/cli/automations.py +20 -7
- prefect/events/clients.py +142 -80
- prefect/events/filters.py +14 -18
- prefect/events/related.py +74 -75
- prefect/events/schemas/__init__.py +0 -5
- prefect/events/schemas/automations.py +55 -46
- prefect/events/schemas/deployment_triggers.py +7 -197
- prefect/events/schemas/events.py +46 -65
- prefect/events/schemas/labelling.py +10 -14
- prefect/events/utilities.py +4 -5
- prefect/events/worker.py +23 -8
- prefect/exceptions.py +15 -0
- prefect/filesystems.py +30 -529
- prefect/flow_engine.py +827 -0
- prefect/flow_runs.py +379 -7
- prefect/flows.py +470 -360
- prefect/futures.py +382 -331
- prefect/infrastructure/__init__.py +5 -26
- prefect/infrastructure/base.py +3 -320
- prefect/infrastructure/provisioners/__init__.py +5 -3
- prefect/infrastructure/provisioners/cloud_run.py +13 -8
- prefect/infrastructure/provisioners/container_instance.py +14 -9
- prefect/infrastructure/provisioners/ecs.py +10 -8
- prefect/infrastructure/provisioners/modal.py +8 -5
- prefect/input/__init__.py +4 -0
- prefect/input/actions.py +2 -4
- prefect/input/run_input.py +9 -9
- prefect/logging/formatters.py +2 -4
- prefect/logging/handlers.py +9 -14
- prefect/logging/loggers.py +5 -5
- prefect/main.py +72 -0
- prefect/plugins.py +2 -64
- prefect/profiles.toml +16 -2
- prefect/records/__init__.py +1 -0
- prefect/records/base.py +223 -0
- prefect/records/filesystem.py +207 -0
- prefect/records/memory.py +178 -0
- prefect/records/result_store.py +64 -0
- prefect/results.py +577 -504
- prefect/runner/runner.py +124 -51
- prefect/runner/server.py +32 -34
- prefect/runner/storage.py +3 -12
- prefect/runner/submit.py +2 -10
- prefect/runner/utils.py +2 -2
- prefect/runtime/__init__.py +1 -0
- prefect/runtime/deployment.py +1 -0
- prefect/runtime/flow_run.py +40 -5
- prefect/runtime/task_run.py +1 -0
- prefect/serializers.py +28 -39
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
- prefect/settings.py +209 -332
- prefect/states.py +160 -63
- prefect/task_engine.py +1478 -57
- prefect/task_runners.py +383 -287
- prefect/task_runs.py +240 -0
- prefect/task_worker.py +463 -0
- prefect/tasks.py +684 -374
- prefect/transactions.py +410 -0
- prefect/types/__init__.py +72 -86
- prefect/types/entrypoint.py +13 -0
- prefect/utilities/annotations.py +4 -3
- prefect/utilities/asyncutils.py +227 -148
- prefect/utilities/callables.py +138 -48
- prefect/utilities/collections.py +134 -86
- prefect/utilities/dispatch.py +27 -14
- prefect/utilities/dockerutils.py +11 -4
- prefect/utilities/engine.py +186 -32
- prefect/utilities/filesystem.py +4 -5
- prefect/utilities/importtools.py +26 -27
- prefect/utilities/pydantic.py +128 -38
- prefect/utilities/schema_tools/hydration.py +18 -1
- prefect/utilities/schema_tools/validation.py +30 -0
- prefect/utilities/services.py +35 -9
- prefect/utilities/templating.py +12 -2
- prefect/utilities/timeout.py +20 -5
- prefect/utilities/urls.py +195 -0
- prefect/utilities/visualization.py +1 -0
- prefect/variables.py +78 -59
- prefect/workers/__init__.py +0 -1
- prefect/workers/base.py +237 -244
- prefect/workers/block.py +5 -226
- prefect/workers/cloud.py +6 -0
- prefect/workers/process.py +265 -12
- prefect/workers/server.py +29 -11
- {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/METADATA +30 -26
- prefect_client-3.0.0.dist-info/RECORD +201 -0
- {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/WHEEL +1 -1
- prefect/_internal/pydantic/_base_model.py +0 -51
- prefect/_internal/pydantic/_compat.py +0 -82
- prefect/_internal/pydantic/_flags.py +0 -20
- prefect/_internal/pydantic/_types.py +0 -8
- prefect/_internal/pydantic/utilities/config_dict.py +0 -72
- prefect/_internal/pydantic/utilities/field_validator.py +0 -150
- prefect/_internal/pydantic/utilities/model_construct.py +0 -56
- prefect/_internal/pydantic/utilities/model_copy.py +0 -55
- prefect/_internal/pydantic/utilities/model_dump.py +0 -136
- prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
- prefect/_internal/pydantic/utilities/model_fields.py +0 -50
- prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
- prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
- prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
- prefect/_internal/pydantic/utilities/model_validate.py +0 -75
- prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
- prefect/_internal/pydantic/utilities/model_validator.py +0 -87
- prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
- prefect/_vendor/fastapi/__init__.py +0 -25
- prefect/_vendor/fastapi/applications.py +0 -946
- prefect/_vendor/fastapi/background.py +0 -3
- prefect/_vendor/fastapi/concurrency.py +0 -44
- prefect/_vendor/fastapi/datastructures.py +0 -58
- prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
- prefect/_vendor/fastapi/dependencies/models.py +0 -64
- prefect/_vendor/fastapi/dependencies/utils.py +0 -877
- prefect/_vendor/fastapi/encoders.py +0 -177
- prefect/_vendor/fastapi/exception_handlers.py +0 -40
- prefect/_vendor/fastapi/exceptions.py +0 -46
- prefect/_vendor/fastapi/logger.py +0 -3
- prefect/_vendor/fastapi/middleware/__init__.py +0 -1
- prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
- prefect/_vendor/fastapi/middleware/cors.py +0 -3
- prefect/_vendor/fastapi/middleware/gzip.py +0 -3
- prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
- prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
- prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
- prefect/_vendor/fastapi/openapi/__init__.py +0 -0
- prefect/_vendor/fastapi/openapi/constants.py +0 -2
- prefect/_vendor/fastapi/openapi/docs.py +0 -203
- prefect/_vendor/fastapi/openapi/models.py +0 -480
- prefect/_vendor/fastapi/openapi/utils.py +0 -485
- prefect/_vendor/fastapi/param_functions.py +0 -340
- prefect/_vendor/fastapi/params.py +0 -453
- prefect/_vendor/fastapi/py.typed +0 -0
- prefect/_vendor/fastapi/requests.py +0 -4
- prefect/_vendor/fastapi/responses.py +0 -40
- prefect/_vendor/fastapi/routing.py +0 -1331
- prefect/_vendor/fastapi/security/__init__.py +0 -15
- prefect/_vendor/fastapi/security/api_key.py +0 -98
- prefect/_vendor/fastapi/security/base.py +0 -6
- prefect/_vendor/fastapi/security/http.py +0 -172
- prefect/_vendor/fastapi/security/oauth2.py +0 -227
- prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
- prefect/_vendor/fastapi/security/utils.py +0 -10
- prefect/_vendor/fastapi/staticfiles.py +0 -1
- prefect/_vendor/fastapi/templating.py +0 -3
- prefect/_vendor/fastapi/testclient.py +0 -1
- prefect/_vendor/fastapi/types.py +0 -3
- prefect/_vendor/fastapi/utils.py +0 -235
- prefect/_vendor/fastapi/websockets.py +0 -7
- prefect/_vendor/starlette/__init__.py +0 -1
- prefect/_vendor/starlette/_compat.py +0 -28
- prefect/_vendor/starlette/_exception_handler.py +0 -80
- prefect/_vendor/starlette/_utils.py +0 -88
- prefect/_vendor/starlette/applications.py +0 -261
- prefect/_vendor/starlette/authentication.py +0 -159
- prefect/_vendor/starlette/background.py +0 -43
- prefect/_vendor/starlette/concurrency.py +0 -59
- prefect/_vendor/starlette/config.py +0 -151
- prefect/_vendor/starlette/convertors.py +0 -87
- prefect/_vendor/starlette/datastructures.py +0 -707
- prefect/_vendor/starlette/endpoints.py +0 -130
- prefect/_vendor/starlette/exceptions.py +0 -60
- prefect/_vendor/starlette/formparsers.py +0 -276
- prefect/_vendor/starlette/middleware/__init__.py +0 -17
- prefect/_vendor/starlette/middleware/authentication.py +0 -52
- prefect/_vendor/starlette/middleware/base.py +0 -220
- prefect/_vendor/starlette/middleware/cors.py +0 -176
- prefect/_vendor/starlette/middleware/errors.py +0 -265
- prefect/_vendor/starlette/middleware/exceptions.py +0 -74
- prefect/_vendor/starlette/middleware/gzip.py +0 -113
- prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
- prefect/_vendor/starlette/middleware/sessions.py +0 -82
- prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
- prefect/_vendor/starlette/middleware/wsgi.py +0 -147
- prefect/_vendor/starlette/py.typed +0 -0
- prefect/_vendor/starlette/requests.py +0 -328
- prefect/_vendor/starlette/responses.py +0 -347
- prefect/_vendor/starlette/routing.py +0 -933
- prefect/_vendor/starlette/schemas.py +0 -154
- prefect/_vendor/starlette/staticfiles.py +0 -248
- prefect/_vendor/starlette/status.py +0 -199
- prefect/_vendor/starlette/templating.py +0 -231
- prefect/_vendor/starlette/testclient.py +0 -804
- prefect/_vendor/starlette/types.py +0 -30
- prefect/_vendor/starlette/websockets.py +0 -193
- prefect/blocks/kubernetes.py +0 -119
- prefect/deprecated/__init__.py +0 -0
- prefect/deprecated/data_documents.py +0 -350
- prefect/deprecated/packaging/__init__.py +0 -12
- prefect/deprecated/packaging/base.py +0 -96
- prefect/deprecated/packaging/docker.py +0 -146
- prefect/deprecated/packaging/file.py +0 -92
- prefect/deprecated/packaging/orion.py +0 -80
- prefect/deprecated/packaging/serializers.py +0 -171
- prefect/events/instrument.py +0 -135
- prefect/infrastructure/container.py +0 -824
- prefect/infrastructure/kubernetes.py +0 -920
- prefect/infrastructure/process.py +0 -289
- prefect/manifests.py +0 -20
- prefect/new_flow_engine.py +0 -449
- prefect/new_task_engine.py +0 -423
- prefect/pydantic/__init__.py +0 -76
- prefect/pydantic/main.py +0 -39
- prefect/software/__init__.py +0 -2
- prefect/software/base.py +0 -50
- prefect/software/conda.py +0 -199
- prefect/software/pip.py +0 -122
- prefect/software/python.py +0 -52
- prefect/task_server.py +0 -322
- prefect_client-2.20.2.dist-info/RECORD +0 -294
- /prefect/{_internal/pydantic/utilities → client/types}/__init__.py +0 -0
- /prefect/{_vendor → concurrency/v1}/__init__.py +0 -0
- {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
- {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/top_level.txt +0 -0
prefect/runner/runner.py
CHANGED
@@ -35,7 +35,6 @@ import datetime
|
|
35
35
|
import inspect
|
36
36
|
import logging
|
37
37
|
import os
|
38
|
-
import shlex
|
39
38
|
import shutil
|
40
39
|
import signal
|
41
40
|
import subprocess
|
@@ -45,7 +44,7 @@ import threading
|
|
45
44
|
from copy import deepcopy
|
46
45
|
from functools import partial
|
47
46
|
from pathlib import Path
|
48
|
-
from typing import Callable, Dict, Iterable, List, Optional, Set, Union
|
47
|
+
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Optional, Set, Union
|
49
48
|
from uuid import UUID, uuid4
|
50
49
|
|
51
50
|
import anyio
|
@@ -65,23 +64,15 @@ from prefect.client.schemas.filters import (
|
|
65
64
|
FlowRunFilterStateName,
|
66
65
|
FlowRunFilterStateType,
|
67
66
|
)
|
68
|
-
from prefect.client.schemas.objects import
|
69
|
-
|
70
|
-
State,
|
71
|
-
StateType,
|
72
|
-
)
|
73
|
-
from prefect.client.schemas.schedules import SCHEDULE_TYPES
|
74
|
-
from prefect.deployments.deployments import load_flow_from_flow_run
|
75
|
-
from prefect.deployments.runner import (
|
76
|
-
EntrypointType,
|
77
|
-
RunnerDeployment,
|
78
|
-
)
|
79
|
-
from prefect.deployments.schedules import FlexibleScheduleList
|
67
|
+
from prefect.client.schemas.objects import Flow as APIFlow
|
68
|
+
from prefect.client.schemas.objects import FlowRun, State, StateType
|
80
69
|
from prefect.events import DeploymentTriggerTypes, TriggerTypes
|
70
|
+
from prefect.events.related import tags_as_related_resources
|
71
|
+
from prefect.events.schemas.events import RelatedResource
|
72
|
+
from prefect.events.utilities import emit_event
|
81
73
|
from prefect.exceptions import Abort, ObjectNotFound
|
82
|
-
from prefect.flows import Flow
|
74
|
+
from prefect.flows import Flow, load_flow_from_flow_run
|
83
75
|
from prefect.logging.loggers import PrefectLogAdapter, flow_run_logger, get_logger
|
84
|
-
from prefect.runner.server import start_webserver
|
85
76
|
from prefect.runner.storage import RunnerStorage
|
86
77
|
from prefect.settings import (
|
87
78
|
PREFECT_API_URL,
|
@@ -91,14 +82,28 @@ from prefect.settings import (
|
|
91
82
|
get_current_settings,
|
92
83
|
)
|
93
84
|
from prefect.states import Crashed, Pending, exception_to_failed_state
|
85
|
+
from prefect.types.entrypoint import EntrypointType
|
94
86
|
from prefect.utilities.asyncutils import (
|
95
87
|
asyncnullcontext,
|
96
88
|
is_async_fn,
|
97
89
|
sync_compatible,
|
98
90
|
)
|
99
91
|
from prefect.utilities.engine import propose_state
|
100
|
-
from prefect.utilities.processutils import
|
101
|
-
|
92
|
+
from prefect.utilities.processutils import (
|
93
|
+
_register_signal,
|
94
|
+
get_sys_executable,
|
95
|
+
run_process,
|
96
|
+
)
|
97
|
+
from prefect.utilities.services import (
|
98
|
+
critical_service_loop,
|
99
|
+
start_client_metrics_server,
|
100
|
+
)
|
101
|
+
from prefect.utilities.slugify import slugify
|
102
|
+
|
103
|
+
if TYPE_CHECKING:
|
104
|
+
from prefect.client.schemas.objects import Deployment
|
105
|
+
from prefect.client.types.flexible_schedule_list import FlexibleScheduleList
|
106
|
+
from prefect.deployments.runner import RunnerDeployment
|
102
107
|
|
103
108
|
__all__ = ["Runner"]
|
104
109
|
|
@@ -130,6 +135,7 @@ class Runner:
|
|
130
135
|
Examples:
|
131
136
|
Set up a Runner to manage the execute of scheduled flow runs for two flows:
|
132
137
|
```python
|
138
|
+
import asyncio
|
133
139
|
from prefect import flow, Runner
|
134
140
|
|
135
141
|
@flow
|
@@ -149,7 +155,7 @@ class Runner:
|
|
149
155
|
# Run on a cron schedule
|
150
156
|
runner.add_flow(goodbye_flow, schedule={"cron": "0 * * * *"})
|
151
157
|
|
152
|
-
runner.start()
|
158
|
+
asyncio.run(runner.start())
|
153
159
|
```
|
154
160
|
"""
|
155
161
|
if name and ("/" in name or "%" in name):
|
@@ -166,30 +172,26 @@ class Runner:
|
|
166
172
|
self.query_seconds = query_seconds or PREFECT_RUNNER_POLL_FREQUENCY.value()
|
167
173
|
self._prefetch_seconds = prefetch_seconds
|
168
174
|
|
169
|
-
self.
|
170
|
-
self._loops_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
|
171
|
-
|
172
|
-
self._limiter: Optional[anyio.CapacityLimiter] = anyio.CapacityLimiter(
|
173
|
-
self.limit
|
174
|
-
)
|
175
|
+
self._limiter: Optional[anyio.CapacityLimiter] = None
|
175
176
|
self._client = get_client()
|
176
177
|
self._submitting_flow_run_ids = set()
|
177
178
|
self._cancelling_flow_run_ids = set()
|
178
179
|
self._scheduled_task_scopes = set()
|
179
180
|
self._deployment_ids: Set[UUID] = set()
|
180
|
-
self._flow_run_process_map = dict()
|
181
|
+
self._flow_run_process_map: Dict[UUID, Dict] = dict()
|
181
182
|
|
182
183
|
self._tmp_dir: Path = (
|
183
184
|
Path(tempfile.gettempdir()) / "runner_storage" / str(uuid4())
|
184
185
|
)
|
185
186
|
self._storage_objs: List[RunnerStorage] = []
|
186
187
|
self._deployment_storage_map: Dict[UUID, RunnerStorage] = {}
|
187
|
-
|
188
|
+
|
189
|
+
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
188
190
|
|
189
191
|
@sync_compatible
|
190
192
|
async def add_deployment(
|
191
193
|
self,
|
192
|
-
deployment: RunnerDeployment,
|
194
|
+
deployment: "RunnerDeployment",
|
193
195
|
) -> UUID:
|
194
196
|
"""
|
195
197
|
Registers the deployment with the Prefect API and will monitor for work once
|
@@ -211,7 +213,7 @@ class Runner:
|
|
211
213
|
async def add_flow(
|
212
214
|
self,
|
213
215
|
flow: Flow,
|
214
|
-
name: str = None,
|
216
|
+
name: Optional[str] = None,
|
215
217
|
interval: Optional[
|
216
218
|
Union[
|
217
219
|
Iterable[Union[int, float, datetime.timedelta]],
|
@@ -223,15 +225,13 @@ class Runner:
|
|
223
225
|
cron: Optional[Union[Iterable[str], str]] = None,
|
224
226
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
225
227
|
paused: Optional[bool] = None,
|
226
|
-
schedules: Optional[FlexibleScheduleList] = None,
|
227
|
-
schedule: Optional[SCHEDULE_TYPES] = None,
|
228
|
-
is_schedule_active: Optional[bool] = None,
|
228
|
+
schedules: Optional["FlexibleScheduleList"] = None,
|
229
229
|
parameters: Optional[dict] = None,
|
230
230
|
triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
231
231
|
description: Optional[str] = None,
|
232
232
|
tags: Optional[List[str]] = None,
|
233
233
|
version: Optional[str] = None,
|
234
|
-
enforce_parameter_schema: bool =
|
234
|
+
enforce_parameter_schema: bool = True,
|
235
235
|
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
236
236
|
) -> UUID:
|
237
237
|
"""
|
@@ -248,11 +248,6 @@ class Runner:
|
|
248
248
|
or a timedelta object. If a number is given, it will be interpreted as seconds.
|
249
249
|
cron: A cron schedule of when to execute runs of this flow.
|
250
250
|
rrule: An rrule schedule of when to execute runs of this flow.
|
251
|
-
schedule: A schedule object of when to execute runs of this flow. Used for
|
252
|
-
advanced scheduling options like timezone.
|
253
|
-
is_schedule_active: Whether or not to set the schedule for this deployment as active. If
|
254
|
-
not provided when creating a deployment, the schedule will be set as active. If not
|
255
|
-
provided when updating a deployment, the schedule's activation will not be changed.
|
256
251
|
triggers: A list of triggers that should kick of a run of this flow.
|
257
252
|
parameters: A dictionary of default parameter values to pass to runs of this flow.
|
258
253
|
description: A description for the created deployment. Defaults to the flow's
|
@@ -277,9 +272,7 @@ class Runner:
|
|
277
272
|
cron=cron,
|
278
273
|
rrule=rrule,
|
279
274
|
schedules=schedules,
|
280
|
-
schedule=schedule,
|
281
275
|
paused=paused,
|
282
|
-
is_schedule_active=is_schedule_active,
|
283
276
|
triggers=triggers,
|
284
277
|
parameters=parameters,
|
285
278
|
description=description,
|
@@ -324,7 +317,6 @@ class Runner:
|
|
324
317
|
|
325
318
|
sys.exit(0)
|
326
319
|
|
327
|
-
@sync_compatible
|
328
320
|
async def start(
|
329
321
|
self, run_once: bool = False, webserver: Optional[bool] = None
|
330
322
|
) -> None:
|
@@ -342,6 +334,7 @@ class Runner:
|
|
342
334
|
Initialize a Runner, add two flows, and serve them by starting the Runner:
|
343
335
|
|
344
336
|
```python
|
337
|
+
import asyncio
|
345
338
|
from prefect import flow, Runner
|
346
339
|
|
347
340
|
@flow
|
@@ -361,9 +354,11 @@ class Runner:
|
|
361
354
|
# Run on a cron schedule
|
362
355
|
runner.add_flow(goodbye_flow, schedule={"cron": "0 * * * *"})
|
363
356
|
|
364
|
-
runner.start()
|
357
|
+
asyncio.run(runner.start())
|
365
358
|
```
|
366
359
|
"""
|
360
|
+
from prefect.runner.server import start_webserver
|
361
|
+
|
367
362
|
_register_signal(signal.SIGTERM, self.handle_sigterm)
|
368
363
|
|
369
364
|
webserver = webserver if webserver is not None else self.webserver
|
@@ -381,6 +376,8 @@ class Runner:
|
|
381
376
|
)
|
382
377
|
server_thread.start()
|
383
378
|
|
379
|
+
start_client_metrics_server()
|
380
|
+
|
384
381
|
async with self as runner:
|
385
382
|
async with self._loops_task_group as tg:
|
386
383
|
for storage in self._storage_objs:
|
@@ -533,7 +530,7 @@ class Runner:
|
|
533
530
|
task_status: anyio task status used to send a message to the caller
|
534
531
|
than the flow run process has started.
|
535
532
|
"""
|
536
|
-
command =
|
533
|
+
command = [get_sys_executable(), "-m", "prefect.engine"]
|
537
534
|
|
538
535
|
flow_run_logger = self._get_flow_run_logger(flow_run)
|
539
536
|
|
@@ -580,7 +577,7 @@ class Runner:
|
|
580
577
|
setattr(storage, "last_adhoc_pull", datetime.datetime.now())
|
581
578
|
|
582
579
|
process = await run_process(
|
583
|
-
|
580
|
+
command=command,
|
584
581
|
stream_output=True,
|
585
582
|
task_status=task_status,
|
586
583
|
env=env,
|
@@ -693,8 +690,9 @@ class Runner:
|
|
693
690
|
"""
|
694
691
|
self._logger.info("Pausing all deployments...")
|
695
692
|
for deployment_id in self._deployment_ids:
|
696
|
-
self._logger.debug(f"Pausing deployment '{deployment_id}'")
|
697
693
|
await self._client.set_deployment_paused_state(deployment_id, True)
|
694
|
+
self._logger.debug(f"Paused deployment '{deployment_id}'")
|
695
|
+
|
698
696
|
self._logger.info("All deployments have been paused!")
|
699
697
|
|
700
698
|
async def _get_and_submit_flow_runs(self):
|
@@ -816,8 +814,71 @@ class Runner:
|
|
816
814
|
"message": state_msg or "Flow run was cancelled successfully."
|
817
815
|
},
|
818
816
|
)
|
817
|
+
try:
|
818
|
+
deployment = await self._client.read_deployment(flow_run.deployment_id)
|
819
|
+
except ObjectNotFound:
|
820
|
+
deployment = None
|
821
|
+
try:
|
822
|
+
flow = await self._client.read_flow(flow_run.flow_id)
|
823
|
+
except ObjectNotFound:
|
824
|
+
flow = None
|
825
|
+
self._emit_flow_run_cancelled_event(
|
826
|
+
flow_run=flow_run, flow=flow, deployment=deployment
|
827
|
+
)
|
819
828
|
run_logger.info(f"Cancelled flow run '{flow_run.name}'!")
|
820
829
|
|
830
|
+
def _event_resource(self):
|
831
|
+
from prefect import __version__
|
832
|
+
|
833
|
+
return {
|
834
|
+
"prefect.resource.id": f"prefect.runner.{slugify(self.name)}",
|
835
|
+
"prefect.resource.name": self.name,
|
836
|
+
"prefect.version": __version__,
|
837
|
+
}
|
838
|
+
|
839
|
+
def _emit_flow_run_cancelled_event(
|
840
|
+
self,
|
841
|
+
flow_run: "FlowRun",
|
842
|
+
flow: "Optional[APIFlow]",
|
843
|
+
deployment: "Optional[Deployment]",
|
844
|
+
):
|
845
|
+
related = []
|
846
|
+
tags = []
|
847
|
+
if deployment:
|
848
|
+
related.append(
|
849
|
+
{
|
850
|
+
"prefect.resource.id": f"prefect.deployment.{deployment.id}",
|
851
|
+
"prefect.resource.role": "deployment",
|
852
|
+
"prefect.resource.name": deployment.name,
|
853
|
+
}
|
854
|
+
)
|
855
|
+
tags.extend(deployment.tags)
|
856
|
+
if flow:
|
857
|
+
related.append(
|
858
|
+
{
|
859
|
+
"prefect.resource.id": f"prefect.flow.{flow.id}",
|
860
|
+
"prefect.resource.role": "flow",
|
861
|
+
"prefect.resource.name": flow.name,
|
862
|
+
}
|
863
|
+
)
|
864
|
+
related.append(
|
865
|
+
{
|
866
|
+
"prefect.resource.id": f"prefect.flow-run.{flow_run.id}",
|
867
|
+
"prefect.resource.role": "flow-run",
|
868
|
+
"prefect.resource.name": flow_run.name,
|
869
|
+
}
|
870
|
+
)
|
871
|
+
tags.extend(flow_run.tags)
|
872
|
+
|
873
|
+
related = [RelatedResource.model_validate(r) for r in related]
|
874
|
+
related += tags_as_related_resources(set(tags))
|
875
|
+
|
876
|
+
emit_event(
|
877
|
+
event="prefect.runner.cancelled-flow-run",
|
878
|
+
resource=self._event_resource(),
|
879
|
+
related=related,
|
880
|
+
)
|
881
|
+
|
821
882
|
async def _get_scheduled_flow_runs(
|
822
883
|
self,
|
823
884
|
) -> List["FlowRun"]:
|
@@ -954,7 +1015,7 @@ class Runner:
|
|
954
1015
|
# If the run is not ready to submit, release the concurrency slot
|
955
1016
|
self._release_limit_slot(flow_run.id)
|
956
1017
|
|
957
|
-
self._submitting_flow_run_ids.
|
1018
|
+
self._submitting_flow_run_ids.discard(flow_run.id)
|
958
1019
|
|
959
1020
|
async def _submit_run_and_capture_errors(
|
960
1021
|
self,
|
@@ -1080,7 +1141,7 @@ class Runner:
|
|
1080
1141
|
state_updates = state_updates or {}
|
1081
1142
|
state_updates.setdefault("name", "Cancelled")
|
1082
1143
|
state_updates.setdefault("type", StateType.CANCELLED)
|
1083
|
-
state = flow_run.state.
|
1144
|
+
state = flow_run.state.model_copy(update=state_updates)
|
1084
1145
|
|
1085
1146
|
await self._client.set_flow_run_state(flow_run.id, state, force=True)
|
1086
1147
|
|
@@ -1130,9 +1191,9 @@ class Runner:
|
|
1130
1191
|
if state.is_cancelling():
|
1131
1192
|
try:
|
1132
1193
|
flow = await load_flow_from_flow_run(
|
1133
|
-
flow_run,
|
1194
|
+
flow_run, storage_base_path=str(self._tmp_dir)
|
1134
1195
|
)
|
1135
|
-
hooks = flow.
|
1196
|
+
hooks = flow.on_cancellation_hooks or []
|
1136
1197
|
|
1137
1198
|
await _run_hooks(hooks, flow_run, flow, state)
|
1138
1199
|
except ObjectNotFound:
|
@@ -1151,9 +1212,9 @@ class Runner:
|
|
1151
1212
|
"""
|
1152
1213
|
if state.is_crashed():
|
1153
1214
|
flow = await load_flow_from_flow_run(
|
1154
|
-
flow_run,
|
1215
|
+
flow_run, storage_base_path=str(self._tmp_dir)
|
1155
1216
|
)
|
1156
|
-
hooks = flow.
|
1217
|
+
hooks = flow.on_crashed_hooks or []
|
1157
1218
|
|
1158
1219
|
await _run_hooks(hooks, flow_run, flow, state)
|
1159
1220
|
|
@@ -1161,6 +1222,18 @@ class Runner:
|
|
1161
1222
|
self._logger.debug("Starting runner...")
|
1162
1223
|
self._client = get_client()
|
1163
1224
|
self._tmp_dir.mkdir(parents=True)
|
1225
|
+
|
1226
|
+
self._limiter = anyio.CapacityLimiter(self.limit)
|
1227
|
+
|
1228
|
+
if not hasattr(self, "_loop") or not self._loop:
|
1229
|
+
self._loop = asyncio.get_event_loop()
|
1230
|
+
|
1231
|
+
if not hasattr(self, "_runs_task_group") or not self._runs_task_group:
|
1232
|
+
self._runs_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
|
1233
|
+
|
1234
|
+
if not hasattr(self, "_loops_task_group") or not self._loops_task_group:
|
1235
|
+
self._loops_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
|
1236
|
+
|
1164
1237
|
await self._client.__aenter__()
|
1165
1238
|
await self._runs_task_group.__aenter__()
|
1166
1239
|
|
prefect/runner/server.py
CHANGED
@@ -3,21 +3,19 @@ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
|
|
3
3
|
|
4
4
|
import pendulum
|
5
5
|
import uvicorn
|
6
|
-
from
|
7
|
-
from
|
6
|
+
from fastapi import APIRouter, FastAPI, HTTPException, status
|
7
|
+
from fastapi.responses import JSONResponse
|
8
8
|
from typing_extensions import Literal
|
9
9
|
|
10
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
11
10
|
from prefect._internal.schemas.validators import validate_values_conform_to_schema
|
12
11
|
from prefect.client.orchestration import get_client
|
13
12
|
from prefect.exceptions import MissingFlowError, ScriptError
|
14
|
-
from prefect.flows import Flow, load_flow_from_entrypoint
|
13
|
+
from prefect.flows import Flow, load_flow_from_entrypoint
|
15
14
|
from prefect.logging import get_logger
|
16
15
|
from prefect.runner.utils import (
|
17
16
|
inject_schemas_into_openapi,
|
18
17
|
)
|
19
18
|
from prefect.settings import (
|
20
|
-
PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS,
|
21
19
|
PREFECT_RUNNER_POLL_FREQUENCY,
|
22
20
|
PREFECT_RUNNER_SERVER_HOST,
|
23
21
|
PREFECT_RUNNER_SERVER_LOG_LEVEL,
|
@@ -25,15 +23,13 @@ from prefect.settings import (
|
|
25
23
|
PREFECT_RUNNER_SERVER_PORT,
|
26
24
|
)
|
27
25
|
from prefect.utilities.asyncutils import sync_compatible
|
26
|
+
from prefect.utilities.importtools import load_script_as_module
|
28
27
|
|
29
28
|
if TYPE_CHECKING:
|
30
29
|
from prefect.client.schemas.responses import DeploymentResponse
|
31
30
|
from prefect.runner import Runner
|
32
31
|
|
33
|
-
|
34
|
-
from pydantic.v1 import BaseModel
|
35
|
-
else:
|
36
|
-
from pydantic import BaseModel
|
32
|
+
from pydantic import BaseModel
|
37
33
|
|
38
34
|
logger = get_logger("webserver")
|
39
35
|
|
@@ -46,7 +42,7 @@ class RunnerGenericFlowRunRequest(BaseModel):
|
|
46
42
|
parent_task_run_id: Optional[uuid.UUID] = None
|
47
43
|
|
48
44
|
|
49
|
-
def perform_health_check(runner, delay_threshold: int = None) -> JSONResponse:
|
45
|
+
def perform_health_check(runner, delay_threshold: Optional[int] = None) -> JSONResponse:
|
50
46
|
if delay_threshold is None:
|
51
47
|
delay_threshold = (
|
52
48
|
PREFECT_RUNNER_SERVER_MISSED_POLLS_TOLERANCE.value()
|
@@ -159,9 +155,12 @@ async def get_subflow_schemas(runner: "Runner") -> Dict[str, Dict]:
|
|
159
155
|
continue
|
160
156
|
|
161
157
|
script = deployment.entrypoint.split(":")[0]
|
162
|
-
|
158
|
+
module = load_script_as_module(script)
|
159
|
+
subflows = [
|
160
|
+
obj for obj in module.__dict__.values() if isinstance(obj, Flow)
|
161
|
+
]
|
163
162
|
for flow in subflows:
|
164
|
-
schemas[flow.name] = flow.parameters.
|
163
|
+
schemas[flow.name] = flow.parameters.model_dump()
|
165
164
|
|
166
165
|
return schemas
|
167
166
|
|
@@ -183,7 +182,7 @@ def _flow_schema_changed(flow: Flow, schemas: Dict[str, Dict]) -> bool:
|
|
183
182
|
flow_name_with_dashes = flow.name.replace("_", "-")
|
184
183
|
|
185
184
|
schema = schemas.get(flow.name, None) or schemas.get(flow_name_with_dashes, None)
|
186
|
-
if schema is not None and flow.parameters.
|
185
|
+
if schema is not None and flow.parameters.model_dump() != schema:
|
187
186
|
return True
|
188
187
|
return False
|
189
188
|
|
@@ -236,7 +235,7 @@ def _build_generic_endpoint_for_flows(
|
|
236
235
|
|
237
236
|
return JSONResponse(
|
238
237
|
status_code=status.HTTP_201_CREATED,
|
239
|
-
content=flow_run.
|
238
|
+
content=flow_run.model_dump(mode="json"),
|
240
239
|
)
|
241
240
|
|
242
241
|
return _create_flow_run_for_flow_from_fqn
|
@@ -261,29 +260,28 @@ async def build_server(runner: "Runner") -> FastAPI:
|
|
261
260
|
router.add_api_route("/shutdown", shutdown(runner=runner), methods=["POST"])
|
262
261
|
webserver.include_router(router)
|
263
262
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
)
|
277
|
-
|
278
|
-
def customize_openapi():
|
279
|
-
if webserver.openapi_schema:
|
280
|
-
return webserver.openapi_schema
|
263
|
+
deployments_router, deployment_schemas = await get_deployment_router(runner)
|
264
|
+
webserver.include_router(deployments_router)
|
265
|
+
|
266
|
+
subflow_schemas = await get_subflow_schemas(runner)
|
267
|
+
webserver.add_api_route(
|
268
|
+
"/flow/run",
|
269
|
+
_build_generic_endpoint_for_flows(runner=runner, schemas=subflow_schemas),
|
270
|
+
methods=["POST"],
|
271
|
+
name="Run flow in background",
|
272
|
+
description="Trigger any flow run as a background task on the runner.",
|
273
|
+
summary="Run flow",
|
274
|
+
)
|
281
275
|
|
282
|
-
|
283
|
-
|
276
|
+
def customize_openapi():
|
277
|
+
if webserver.openapi_schema:
|
284
278
|
return webserver.openapi_schema
|
285
279
|
|
286
|
-
|
280
|
+
openapi_schema = inject_schemas_into_openapi(webserver, deployment_schemas)
|
281
|
+
webserver.openapi_schema = openapi_schema
|
282
|
+
return webserver.openapi_schema
|
283
|
+
|
284
|
+
webserver.openapi = customize_openapi
|
287
285
|
|
288
286
|
return webserver
|
289
287
|
|
prefect/runner/storage.py
CHANGED
@@ -8,20 +8,15 @@ from uuid import uuid4
|
|
8
8
|
|
9
9
|
import fsspec
|
10
10
|
from anyio import run_process
|
11
|
+
from pydantic import SecretStr
|
11
12
|
|
12
13
|
from prefect._internal.concurrency.api import create_call, from_async
|
13
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
14
14
|
from prefect.blocks.core import Block, BlockNotSavedError
|
15
15
|
from prefect.blocks.system import Secret
|
16
16
|
from prefect.filesystems import ReadableDeploymentStorage, WritableDeploymentStorage
|
17
17
|
from prefect.logging.loggers import get_logger
|
18
18
|
from prefect.utilities.collections import visit_collection
|
19
19
|
|
20
|
-
if HAS_PYDANTIC_V2:
|
21
|
-
from pydantic.v1 import SecretStr
|
22
|
-
else:
|
23
|
-
from pydantic import SecretStr
|
24
|
-
|
25
20
|
|
26
21
|
@runtime_checkable
|
27
22
|
class RunnerStorage(Protocol):
|
@@ -159,7 +154,7 @@ class GitRepository:
|
|
159
154
|
url_components = urlparse(self._url)
|
160
155
|
|
161
156
|
credentials = (
|
162
|
-
self._credentials.
|
157
|
+
self._credentials.model_dump()
|
163
158
|
if isinstance(self._credentials, Block)
|
164
159
|
else deepcopy(self._credentials)
|
165
160
|
)
|
@@ -396,7 +391,7 @@ class RemoteStorage:
|
|
396
391
|
if hasattr(obj, "value"):
|
397
392
|
return obj.value
|
398
393
|
else:
|
399
|
-
return obj.
|
394
|
+
return obj.model_dump()
|
400
395
|
return obj
|
401
396
|
|
402
397
|
settings_with_block_values = visit_collection(
|
@@ -571,16 +566,12 @@ class BlockStorageAdapter:
|
|
571
566
|
class LocalStorage:
|
572
567
|
"""
|
573
568
|
Sets the working directory in the local filesystem.
|
574
|
-
|
575
569
|
Parameters:
|
576
570
|
Path: Local file path to set the working directory for the flow
|
577
|
-
|
578
571
|
Examples:
|
579
572
|
Sets the working directory for the local path to the flow:
|
580
|
-
|
581
573
|
```python
|
582
574
|
from prefect.runner.storage import Localstorage
|
583
|
-
|
584
575
|
storage = LocalStorage(
|
585
576
|
path="/path/to/local/flow_directory",
|
586
577
|
)
|
prefect/runner/submit.py
CHANGED
@@ -14,7 +14,6 @@ from prefect.context import FlowRunContext
|
|
14
14
|
from prefect.flows import Flow
|
15
15
|
from prefect.logging import get_logger
|
16
16
|
from prefect.settings import (
|
17
|
-
PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS,
|
18
17
|
PREFECT_RUNNER_PROCESS_LIMIT,
|
19
18
|
PREFECT_RUNNER_SERVER_HOST,
|
20
19
|
PREFECT_RUNNER_SERVER_PORT,
|
@@ -43,7 +42,7 @@ async def _submit_flow_to_runner(
|
|
43
42
|
Returns:
|
44
43
|
A `FlowRun` object representing the flow run that was submitted.
|
45
44
|
"""
|
46
|
-
from prefect.engine import (
|
45
|
+
from prefect.utilities.engine import (
|
47
46
|
_dynamic_key_for_task_run,
|
48
47
|
collect_task_run_inputs,
|
49
48
|
resolve_inputs,
|
@@ -90,7 +89,7 @@ async def _submit_flow_to_runner(
|
|
90
89
|
)
|
91
90
|
response.raise_for_status()
|
92
91
|
|
93
|
-
return FlowRun.
|
92
|
+
return FlowRun.model_validate(response.json())
|
94
93
|
|
95
94
|
|
96
95
|
@overload
|
@@ -131,13 +130,6 @@ async def submit_to_runner(
|
|
131
130
|
"The `submit_to_runner` utility only supports submitting flows and tasks."
|
132
131
|
)
|
133
132
|
|
134
|
-
if not PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS.value():
|
135
|
-
raise ValueError(
|
136
|
-
"The `submit_to_runner` utility requires the `Runner` webserver to be"
|
137
|
-
" running and built with extra endpoints enabled. To enable this, set the"
|
138
|
-
" `PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS` setting to `True`."
|
139
|
-
)
|
140
|
-
|
141
133
|
parameters = parameters or {}
|
142
134
|
if isinstance(parameters, List):
|
143
135
|
return_single = False
|
prefect/runner/utils.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
from copy import deepcopy
|
2
2
|
from typing import Any, Dict
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
4
|
+
from fastapi import FastAPI
|
5
|
+
from fastapi.openapi.utils import get_openapi
|
6
6
|
|
7
7
|
from prefect import __version__ as PREFECT_VERSION
|
8
8
|
|
prefect/runtime/__init__.py
CHANGED
prefect/runtime/deployment.py
CHANGED