prefect-client 3.0.0rc10__py3-none-any.whl → 3.0.0rc11__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/_internal/concurrency/api.py +1 -1
- prefect/_internal/retries.py +61 -0
- prefect/client/cloud.py +1 -1
- prefect/client/schemas/objects.py +1 -1
- prefect/concurrency/asyncio.py +3 -3
- prefect/concurrency/events.py +1 -1
- prefect/concurrency/services.py +3 -2
- prefect/concurrency/sync.py +19 -5
- prefect/context.py +8 -2
- prefect/deployments/__init__.py +28 -15
- prefect/deployments/steps/pull.py +7 -0
- prefect/flow_engine.py +5 -7
- prefect/flows.py +179 -65
- prefect/futures.py +53 -7
- prefect/logging/loggers.py +1 -1
- prefect/runner/runner.py +93 -20
- prefect/runner/server.py +20 -22
- prefect/runner/submit.py +0 -8
- prefect/runtime/flow_run.py +38 -3
- prefect/settings.py +9 -13
- prefect/task_worker.py +1 -1
- prefect/transactions.py +16 -0
- prefect/utilities/asyncutils.py +1 -0
- prefect/utilities/engine.py +34 -1
- prefect/workers/base.py +98 -208
- prefect/workers/process.py +262 -4
- prefect/workers/server.py +27 -9
- {prefect_client-3.0.0rc10.dist-info → prefect_client-3.0.0rc11.dist-info}/METADATA +3 -3
- {prefect_client-3.0.0rc10.dist-info → prefect_client-3.0.0rc11.dist-info}/RECORD +32 -31
- {prefect_client-3.0.0rc10.dist-info → prefect_client-3.0.0rc11.dist-info}/LICENSE +0 -0
- {prefect_client-3.0.0rc10.dist-info → prefect_client-3.0.0rc11.dist-info}/WHEEL +0 -0
- {prefect_client-3.0.0rc10.dist-info → prefect_client-3.0.0rc11.dist-info}/top_level.txt +0 -0
prefect/runner/server.py
CHANGED
@@ -16,7 +16,6 @@ from prefect.runner.utils import (
|
|
16
16
|
inject_schemas_into_openapi,
|
17
17
|
)
|
18
18
|
from prefect.settings import (
|
19
|
-
PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS,
|
20
19
|
PREFECT_RUNNER_POLL_FREQUENCY,
|
21
20
|
PREFECT_RUNNER_SERVER_HOST,
|
22
21
|
PREFECT_RUNNER_SERVER_LOG_LEVEL,
|
@@ -202,7 +201,7 @@ def _build_generic_endpoint_for_flows(
|
|
202
201
|
|
203
202
|
try:
|
204
203
|
flow = load_flow_from_entrypoint(body.entrypoint)
|
205
|
-
except (MissingFlowError, ScriptError, ModuleNotFoundError):
|
204
|
+
except (FileNotFoundError, MissingFlowError, ScriptError, ModuleNotFoundError):
|
206
205
|
return JSONResponse(
|
207
206
|
status_code=status.HTTP_404_NOT_FOUND,
|
208
207
|
content={"message": "Flow not found"},
|
@@ -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/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,
|
@@ -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/runtime/flow_run.py
CHANGED
@@ -38,6 +38,7 @@ __all__ = [
|
|
38
38
|
"parameters",
|
39
39
|
"parent_flow_run_id",
|
40
40
|
"parent_deployment_id",
|
41
|
+
"root_flow_run_id",
|
41
42
|
"run_count",
|
42
43
|
"api_url",
|
43
44
|
"ui_url",
|
@@ -237,11 +238,12 @@ def get_parent_flow_run_id() -> Optional[str]:
|
|
237
238
|
parent_task_run = from_sync.call_soon_in_loop_thread(
|
238
239
|
create_call(_get_task_run, parent_task_run_id)
|
239
240
|
).result()
|
240
|
-
return parent_task_run.flow_run_id
|
241
|
+
return str(parent_task_run.flow_run_id) if parent_task_run.flow_run_id else None
|
242
|
+
|
241
243
|
return None
|
242
244
|
|
243
245
|
|
244
|
-
def get_parent_deployment_id() ->
|
246
|
+
def get_parent_deployment_id() -> Optional[str]:
|
245
247
|
parent_flow_run_id = get_parent_flow_run_id()
|
246
248
|
if parent_flow_run_id is None:
|
247
249
|
return None
|
@@ -249,7 +251,39 @@ def get_parent_deployment_id() -> Dict[str, Any]:
|
|
249
251
|
parent_flow_run = from_sync.call_soon_in_loop_thread(
|
250
252
|
create_call(_get_flow_run, parent_flow_run_id)
|
251
253
|
).result()
|
252
|
-
|
254
|
+
|
255
|
+
if parent_flow_run:
|
256
|
+
return (
|
257
|
+
str(parent_flow_run.deployment_id)
|
258
|
+
if parent_flow_run.deployment_id
|
259
|
+
else None
|
260
|
+
)
|
261
|
+
|
262
|
+
return None
|
263
|
+
|
264
|
+
|
265
|
+
def get_root_flow_run_id() -> str:
|
266
|
+
run_id = get_id()
|
267
|
+
parent_flow_run_id = get_parent_flow_run_id()
|
268
|
+
if parent_flow_run_id is None:
|
269
|
+
return run_id
|
270
|
+
|
271
|
+
def _get_root_flow_run_id(flow_run_id):
|
272
|
+
flow_run = from_sync.call_soon_in_loop_thread(
|
273
|
+
create_call(_get_flow_run, flow_run_id)
|
274
|
+
).result()
|
275
|
+
|
276
|
+
if flow_run.parent_task_run_id is None:
|
277
|
+
return str(flow_run_id)
|
278
|
+
else:
|
279
|
+
parent_task_run = from_sync.call_soon_in_loop_thread(
|
280
|
+
create_call(_get_task_run, flow_run.parent_task_run_id)
|
281
|
+
).result()
|
282
|
+
return _get_root_flow_run_id(parent_task_run.flow_run_id)
|
283
|
+
|
284
|
+
root_flow_run_id = _get_root_flow_run_id(parent_flow_run_id)
|
285
|
+
|
286
|
+
return root_flow_run_id
|
253
287
|
|
254
288
|
|
255
289
|
def get_flow_run_api_url() -> Optional[str]:
|
@@ -275,6 +309,7 @@ FIELDS = {
|
|
275
309
|
"parameters": get_parameters,
|
276
310
|
"parent_flow_run_id": get_parent_flow_run_id,
|
277
311
|
"parent_deployment_id": get_parent_deployment_id,
|
312
|
+
"root_flow_run_id": get_root_flow_run_id,
|
278
313
|
"run_count": get_run_count,
|
279
314
|
"api_url": get_flow_run_api_url,
|
280
315
|
"ui_url": get_flow_run_ui_url,
|
prefect/settings.py
CHANGED
@@ -1160,6 +1160,11 @@ polled."""
|
|
1160
1160
|
PREFECT_API_LOG_RETRYABLE_ERRORS = Setting(bool, default=False)
|
1161
1161
|
"""If `True`, log retryable errors in the API and it's services."""
|
1162
1162
|
|
1163
|
+
PREFECT_API_SERVICES_TASK_RUN_RECORDER_ENABLED = Setting(bool, default=True)
|
1164
|
+
"""
|
1165
|
+
Whether or not to start the task run recorder service in the server application.
|
1166
|
+
"""
|
1167
|
+
|
1163
1168
|
|
1164
1169
|
PREFECT_API_DEFAULT_LIMIT = Setting(
|
1165
1170
|
int,
|
@@ -1309,17 +1314,13 @@ The maximum number of artifacts to show on a flow run graph on the v2 API
|
|
1309
1314
|
"""
|
1310
1315
|
|
1311
1316
|
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
"""
|
1316
|
-
|
1317
|
-
PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION = Setting(bool, default=False)
|
1317
|
+
PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION = Setting(
|
1318
|
+
bool, default=False
|
1319
|
+
)
|
1318
1320
|
"""
|
1319
|
-
Whether or not to
|
1321
|
+
Whether or not to enable experimental client side task run orchestration.
|
1320
1322
|
"""
|
1321
1323
|
|
1322
|
-
|
1323
1324
|
# Prefect Events feature flags
|
1324
1325
|
|
1325
1326
|
PREFECT_RUNNER_PROCESS_LIMIT = Setting(int, default=5)
|
@@ -1437,11 +1438,6 @@ a task worker should move a task from PENDING to RUNNING very quickly, so runs s
|
|
1437
1438
|
PENDING for a while is a sign that the task worker may have crashed.
|
1438
1439
|
"""
|
1439
1440
|
|
1440
|
-
PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS = Setting(bool, default=False)
|
1441
|
-
"""
|
1442
|
-
Whether or not to enable experimental worker webserver endpoints.
|
1443
|
-
"""
|
1444
|
-
|
1445
1441
|
PREFECT_EXPERIMENTAL_DISABLE_SYNC_COMPAT = Setting(bool, default=False)
|
1446
1442
|
"""
|
1447
1443
|
Whether or not to disable the sync_compatible decorator utility.
|
prefect/task_worker.py
CHANGED
@@ -325,7 +325,7 @@ class TaskWorker:
|
|
325
325
|
|
326
326
|
if task_run_url := url_for(task_run):
|
327
327
|
logger.info(
|
328
|
-
f"Submitting task run {task_run.name!r} to engine. View
|
328
|
+
f"Submitting task run {task_run.name!r} to engine. View in the UI: {task_run_url}"
|
329
329
|
)
|
330
330
|
|
331
331
|
if task.isasync:
|
prefect/transactions.py
CHANGED
@@ -187,8 +187,16 @@ class Transaction(ContextModel):
|
|
187
187
|
|
188
188
|
for hook in self.on_commit_hooks:
|
189
189
|
hook_name = _get_hook_name(hook)
|
190
|
+
if self.logger:
|
191
|
+
self.logger.info(f"Running commit hook {hook_name!r}")
|
192
|
+
|
190
193
|
hook(self)
|
191
194
|
|
195
|
+
if self.logger:
|
196
|
+
self.logger.info(
|
197
|
+
f"Commit hook {hook_name!r} finished running successfully"
|
198
|
+
)
|
199
|
+
|
192
200
|
if self.store and self.key:
|
193
201
|
self.store.write(key=self.key, value=self._staged_value)
|
194
202
|
self.state = TransactionState.COMMITTED
|
@@ -235,8 +243,16 @@ class Transaction(ContextModel):
|
|
235
243
|
try:
|
236
244
|
for hook in reversed(self.on_rollback_hooks):
|
237
245
|
hook_name = _get_hook_name(hook)
|
246
|
+
if self.logger:
|
247
|
+
self.logger.info(f"Running rollback hook {hook_name!r}")
|
248
|
+
|
238
249
|
hook(self)
|
239
250
|
|
251
|
+
if self.logger:
|
252
|
+
self.logger.info(
|
253
|
+
f"Rollback hook {hook_name!r} finished running successfully"
|
254
|
+
)
|
255
|
+
|
240
256
|
self.state = TransactionState.ROLLED_BACK
|
241
257
|
|
242
258
|
for child in reversed(self.children):
|
prefect/utilities/asyncutils.py
CHANGED
prefect/utilities/engine.py
CHANGED
@@ -51,6 +51,7 @@ from prefect.logging.loggers import (
|
|
51
51
|
)
|
52
52
|
from prefect.results import BaseResult
|
53
53
|
from prefect.settings import (
|
54
|
+
PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION,
|
54
55
|
PREFECT_LOGGING_LOG_PRINTS,
|
55
56
|
)
|
56
57
|
from prefect.states import (
|
@@ -558,7 +559,7 @@ def propose_state_sync(
|
|
558
559
|
)
|
559
560
|
|
560
561
|
|
561
|
-
def _dynamic_key_for_task_run(context: FlowRunContext, task: Task) -> int:
|
562
|
+
def _dynamic_key_for_task_run(context: FlowRunContext, task: Task) -> Union[int, str]:
|
562
563
|
if context.detached: # this task is running on remote infrastructure
|
563
564
|
return str(uuid4())
|
564
565
|
elif context.flow_run is None: # this is an autonomous task run
|
@@ -744,6 +745,12 @@ def emit_task_run_state_change_event(
|
|
744
745
|
"message": truncated_to(
|
745
746
|
state_message_truncation_length, initial_state.message
|
746
747
|
),
|
748
|
+
"state_details": initial_state.state_details.model_dump(
|
749
|
+
mode="json",
|
750
|
+
exclude_none=True,
|
751
|
+
exclude_unset=True,
|
752
|
+
exclude={"flow_run_id", "task_run_id"},
|
753
|
+
),
|
747
754
|
}
|
748
755
|
if initial_state
|
749
756
|
else None
|
@@ -754,7 +761,30 @@ def emit_task_run_state_change_event(
|
|
754
761
|
"message": truncated_to(
|
755
762
|
state_message_truncation_length, validated_state.message
|
756
763
|
),
|
764
|
+
"state_details": validated_state.state_details.model_dump(
|
765
|
+
mode="json",
|
766
|
+
exclude_none=True,
|
767
|
+
exclude_unset=True,
|
768
|
+
exclude={"flow_run_id", "task_run_id"},
|
769
|
+
),
|
770
|
+
"data": validated_state.data.model_dump(mode="json")
|
771
|
+
if isinstance(validated_state.data, BaseResult)
|
772
|
+
else None,
|
757
773
|
},
|
774
|
+
"task_run": task_run.model_dump(
|
775
|
+
mode="json",
|
776
|
+
exclude_none=True,
|
777
|
+
exclude={
|
778
|
+
"id",
|
779
|
+
"created",
|
780
|
+
"updated",
|
781
|
+
"flow_run_id",
|
782
|
+
"state_id",
|
783
|
+
"state_type",
|
784
|
+
"state_name",
|
785
|
+
"state",
|
786
|
+
},
|
787
|
+
),
|
758
788
|
},
|
759
789
|
resource={
|
760
790
|
"prefect.resource.id": f"prefect.task-run.{task_run.id}",
|
@@ -769,6 +799,9 @@ def emit_task_run_state_change_event(
|
|
769
799
|
else ""
|
770
800
|
),
|
771
801
|
"prefect.state-type": str(validated_state.type.value),
|
802
|
+
"prefect.orchestration": "client"
|
803
|
+
if PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION
|
804
|
+
else "server",
|
772
805
|
},
|
773
806
|
follows=follows,
|
774
807
|
)
|