prefect-client 2.16.1__py3-none-any.whl → 2.16.3__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/services.py +5 -0
- prefect/_internal/concurrency/threads.py +3 -0
- prefect/client/orchestration.py +18 -0
- prefect/deployments/__init__.py +6 -1
- prefect/deployments/deployments.py +48 -8
- prefect/deployments/runner.py +72 -54
- prefect/deployments/schedules.py +37 -0
- prefect/engine.py +62 -23
- prefect/events/schemas.py +253 -43
- prefect/flows.py +71 -20
- prefect/logging/filters.py +25 -3
- prefect/results.py +78 -2
- prefect/runner/runner.py +10 -2
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +9 -2
- prefect/settings.py +63 -10
- prefect/task_engine.py +17 -9
- prefect/task_server.py +2 -1
- prefect/tasks.py +39 -4
- prefect/utilities/schema_tools/__init__.py +0 -0
- prefect/utilities/schema_tools/hydration.py +218 -0
- prefect/utilities/schema_tools/validation.py +240 -0
- {prefect_client-2.16.1.dist-info → prefect_client-2.16.3.dist-info}/METADATA +52 -49
- {prefect_client-2.16.1.dist-info → prefect_client-2.16.3.dist-info}/RECORD +26 -22
- {prefect_client-2.16.1.dist-info → prefect_client-2.16.3.dist-info}/LICENSE +0 -0
- {prefect_client-2.16.1.dist-info → prefect_client-2.16.3.dist-info}/WHEEL +0 -0
- {prefect_client-2.16.1.dist-info → prefect_client-2.16.3.dist-info}/top_level.txt +0 -0
prefect/flows.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
Module containing the base workflow class and decorator - for most use cases, using the [`@flow` decorator][prefect.flows.flow] is preferred.
|
3
3
|
"""
|
4
|
+
|
4
5
|
# This file requires type-checking with pyright because mypy does not yet support PEP612
|
5
6
|
# See https://github.com/python/mypy/issues/8645
|
6
7
|
|
@@ -40,7 +41,7 @@ from prefect._internal.compatibility.deprecated import deprecated_parameter
|
|
40
41
|
from prefect._internal.concurrency.api import create_call, from_async
|
41
42
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
42
43
|
from prefect.client.orchestration import get_client
|
43
|
-
from prefect.deployments.runner import DeploymentImage, deploy
|
44
|
+
from prefect.deployments.runner import DeploymentImage, EntrypointType, deploy
|
44
45
|
from prefect.filesystems import ReadableDeploymentStorage
|
45
46
|
from prefect.runner.storage import (
|
46
47
|
BlockStorageAdapter,
|
@@ -182,6 +183,7 @@ class Flow(Generic[P, R]):
|
|
182
183
|
on_completion: An optional list of callables to run when the flow enters a completed state.
|
183
184
|
on_cancellation: An optional list of callables to run when the flow enters a cancelling state.
|
184
185
|
on_crashed: An optional list of callables to run when the flow enters a crashed state.
|
186
|
+
on_running: An optional list of callables to run when the flow enters a running state.
|
185
187
|
"""
|
186
188
|
|
187
189
|
# NOTE: These parameters (types, defaults, and docstrings) should be duplicated
|
@@ -211,6 +213,7 @@ class Flow(Generic[P, R]):
|
|
211
213
|
List[Callable[[FlowSchema, FlowRun, State], None]]
|
212
214
|
] = None,
|
213
215
|
on_crashed: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
216
|
+
on_running: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
214
217
|
):
|
215
218
|
if name is not None and not isinstance(name, str):
|
216
219
|
raise TypeError(
|
@@ -226,8 +229,20 @@ class Flow(Generic[P, R]):
|
|
226
229
|
)
|
227
230
|
|
228
231
|
# Validate if hook passed is list and contains callables
|
229
|
-
hook_categories = [
|
230
|
-
|
232
|
+
hook_categories = [
|
233
|
+
on_completion,
|
234
|
+
on_failure,
|
235
|
+
on_cancellation,
|
236
|
+
on_crashed,
|
237
|
+
on_running,
|
238
|
+
]
|
239
|
+
hook_names = [
|
240
|
+
"on_completion",
|
241
|
+
"on_failure",
|
242
|
+
"on_cancellation",
|
243
|
+
"on_crashed",
|
244
|
+
"on_running",
|
245
|
+
]
|
231
246
|
for hooks, hook_name in zip(hook_categories, hook_names):
|
232
247
|
if hooks is not None:
|
233
248
|
if not hooks:
|
@@ -349,6 +364,7 @@ class Flow(Generic[P, R]):
|
|
349
364
|
self.on_failure = on_failure
|
350
365
|
self.on_cancellation = on_cancellation
|
351
366
|
self.on_crashed = on_crashed
|
367
|
+
self.on_running = on_running
|
352
368
|
|
353
369
|
# Used for flows loaded from remote storage
|
354
370
|
self._storage: Optional[RunnerStorage] = None
|
@@ -386,6 +402,7 @@ class Flow(Generic[P, R]):
|
|
386
402
|
List[Callable[[FlowSchema, FlowRun, State], None]]
|
387
403
|
] = None,
|
388
404
|
on_crashed: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
405
|
+
on_running: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
389
406
|
) -> Self:
|
390
407
|
"""
|
391
408
|
Create a new flow from the current object, updating provided options.
|
@@ -414,6 +431,7 @@ class Flow(Generic[P, R]):
|
|
414
431
|
on_completion: A new list of callables to run when the flow enters a completed state.
|
415
432
|
on_cancellation: A new list of callables to run when the flow enters a cancelling state.
|
416
433
|
on_crashed: A new list of callables to run when the flow enters a crashed state.
|
434
|
+
on_running: A new list of callables to run when the flow enters a running state.
|
417
435
|
|
418
436
|
Returns:
|
419
437
|
A new `Flow` instance.
|
@@ -449,9 +467,11 @@ class Flow(Generic[P, R]):
|
|
449
467
|
version=version or self.version,
|
450
468
|
task_runner=task_runner or self.task_runner,
|
451
469
|
retries=retries if retries is not None else self.retries,
|
452
|
-
retry_delay_seconds=
|
453
|
-
|
454
|
-
|
470
|
+
retry_delay_seconds=(
|
471
|
+
retry_delay_seconds
|
472
|
+
if retry_delay_seconds is not None
|
473
|
+
else self.retry_delay_seconds
|
474
|
+
),
|
455
475
|
timeout_seconds=(
|
456
476
|
timeout_seconds if timeout_seconds is not None else self.timeout_seconds
|
457
477
|
),
|
@@ -481,6 +501,7 @@ class Flow(Generic[P, R]):
|
|
481
501
|
on_failure=on_failure or self.on_failure,
|
482
502
|
on_cancellation=on_cancellation or self.on_cancellation,
|
483
503
|
on_crashed=on_crashed or self.on_crashed,
|
504
|
+
on_running=on_running or self.on_running,
|
484
505
|
)
|
485
506
|
new_flow._storage = self._storage
|
486
507
|
new_flow._entrypoint = self._entrypoint
|
@@ -605,6 +626,7 @@ class Flow(Generic[P, R]):
|
|
605
626
|
work_pool_name: Optional[str] = None,
|
606
627
|
work_queue_name: Optional[str] = None,
|
607
628
|
job_variables: Optional[Dict[str, Any]] = None,
|
629
|
+
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
608
630
|
) -> "RunnerDeployment":
|
609
631
|
"""
|
610
632
|
Creates a runner deployment object for this flow.
|
@@ -617,7 +639,7 @@ class Flow(Generic[P, R]):
|
|
617
639
|
rrule: An rrule schedule of when to execute runs of this deployment.
|
618
640
|
paused: Whether or not to set this deployment as paused.
|
619
641
|
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
620
|
-
Used to define multiple schedules or additional scheduling options
|
642
|
+
Used to define multiple schedules or additional scheduling options such as `timezone`.
|
621
643
|
schedule: A schedule object defining when to execute runs of this deployment.
|
622
644
|
is_schedule_active: Whether or not to set the schedule for this deployment as active. If
|
623
645
|
not provided when creating a deployment, the schedule will be set as active. If not
|
@@ -636,6 +658,8 @@ class Flow(Generic[P, R]):
|
|
636
658
|
If not provided the default work queue for the work pool will be used.
|
637
659
|
job_variables: Settings used to override the values specified default base job template
|
638
660
|
of the chosen work pool. Refer to the base job template of the chosen work pool for
|
661
|
+
entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
|
662
|
+
entrypoint, ensure that the module will be importable in the execution environment.
|
639
663
|
|
640
664
|
Examples:
|
641
665
|
Prepare two deployments and serve them:
|
@@ -703,6 +727,7 @@ class Flow(Generic[P, R]):
|
|
703
727
|
work_pool_name=work_pool_name,
|
704
728
|
work_queue_name=work_queue_name,
|
705
729
|
job_variables=job_variables,
|
730
|
+
entrypoint_type=entrypoint_type,
|
706
731
|
)
|
707
732
|
|
708
733
|
@sync_compatible
|
@@ -733,22 +758,27 @@ class Flow(Generic[P, R]):
|
|
733
758
|
print_starting_message: bool = True,
|
734
759
|
limit: Optional[int] = None,
|
735
760
|
webserver: bool = False,
|
761
|
+
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
736
762
|
):
|
737
763
|
"""
|
738
764
|
Creates a deployment for this flow and starts a runner to monitor for scheduled work.
|
739
765
|
|
740
766
|
Args:
|
741
767
|
name: The name to give the created deployment.
|
742
|
-
interval: An interval on which to execute the
|
743
|
-
|
744
|
-
|
745
|
-
|
768
|
+
interval: An interval on which to execute the deployment. Accepts a number or a
|
769
|
+
timedelta object to create a single schedule. If a number is given, it will be
|
770
|
+
interpreted as seconds. Also accepts an iterable of numbers or timedelta to create
|
771
|
+
multiple schedules.
|
772
|
+
cron: A cron schedule string of when to execute runs of this deployment.
|
773
|
+
Also accepts an iterable of cron schedule strings to create multiple schedules.
|
774
|
+
rrule: An rrule schedule string of when to execute runs of this deployment.
|
775
|
+
Also accepts an iterable of rrule schedule strings to create multiple schedules.
|
746
776
|
triggers: A list of triggers that will kick off runs of this deployment.
|
747
777
|
paused: Whether or not to set this deployment as paused.
|
748
778
|
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
749
779
|
Used to define multiple schedules or additional scheduling options like `timezone`.
|
750
780
|
schedule: A schedule object defining when to execute runs of this deployment. Used to
|
751
|
-
define additional scheduling options
|
781
|
+
define additional scheduling options such as `timezone`.
|
752
782
|
is_schedule_active: Whether or not to set the schedule for this deployment as active. If
|
753
783
|
not provided when creating a deployment, the schedule will be set as active. If not
|
754
784
|
provided when updating a deployment, the schedule's activation will not be changed.
|
@@ -765,6 +795,8 @@ class Flow(Generic[P, R]):
|
|
765
795
|
print_starting_message: Whether or not to print the starting message when flow is served.
|
766
796
|
limit: The maximum number of runs that can be executed concurrently.
|
767
797
|
webserver: Whether or not to start a monitoring webserver for this flow.
|
798
|
+
entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
|
799
|
+
entrypoint, ensure that the module will be importable in the execution environment.
|
768
800
|
|
769
801
|
Examples:
|
770
802
|
Serve a flow:
|
@@ -817,6 +849,7 @@ class Flow(Generic[P, R]):
|
|
817
849
|
tags=tags,
|
818
850
|
version=version,
|
819
851
|
enforce_parameter_schema=enforce_parameter_schema,
|
852
|
+
entrypoint_type=entrypoint_type,
|
820
853
|
)
|
821
854
|
if print_starting_message:
|
822
855
|
help_message = (
|
@@ -935,6 +968,7 @@ class Flow(Generic[P, R]):
|
|
935
968
|
tags: Optional[List[str]] = None,
|
936
969
|
version: Optional[str] = None,
|
937
970
|
enforce_parameter_schema: bool = False,
|
971
|
+
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
938
972
|
print_next_steps: bool = True,
|
939
973
|
) -> UUID:
|
940
974
|
"""
|
@@ -961,10 +995,14 @@ class Flow(Generic[P, R]):
|
|
961
995
|
job_variables: Settings used to override the values specified default base job template
|
962
996
|
of the chosen work pool. Refer to the base job template of the chosen work pool for
|
963
997
|
available settings.
|
964
|
-
interval: An interval on which to execute the
|
965
|
-
|
966
|
-
|
967
|
-
|
998
|
+
interval: An interval on which to execute the deployment. Accepts a number or a
|
999
|
+
timedelta object to create a single schedule. If a number is given, it will be
|
1000
|
+
interpreted as seconds. Also accepts an iterable of numbers or timedelta to create
|
1001
|
+
multiple schedules.
|
1002
|
+
cron: A cron schedule string of when to execute runs of this deployment.
|
1003
|
+
Also accepts an iterable of cron schedule strings to create multiple schedules.
|
1004
|
+
rrule: An rrule schedule string of when to execute runs of this deployment.
|
1005
|
+
Also accepts an iterable of rrule schedule strings to create multiple schedules.
|
968
1006
|
triggers: A list of triggers that will kick off runs of this deployment.
|
969
1007
|
paused: Whether or not to set this deployment as paused.
|
970
1008
|
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
@@ -982,8 +1020,10 @@ class Flow(Generic[P, R]):
|
|
982
1020
|
version: A version for the created deployment. Defaults to the flow's version.
|
983
1021
|
enforce_parameter_schema: Whether or not the Prefect API should enforce the
|
984
1022
|
parameter schema for the created deployment.
|
1023
|
+
entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
|
1024
|
+
entrypoint, ensure that the module will be importable in the execution environment.
|
985
1025
|
print_next_steps_message: Whether or not to print a message with next steps
|
986
|
-
|
1026
|
+
after deploying the deployments.
|
987
1027
|
|
988
1028
|
Returns:
|
989
1029
|
The ID of the created/updated deployment.
|
@@ -1050,6 +1090,7 @@ class Flow(Generic[P, R]):
|
|
1050
1090
|
enforce_parameter_schema=enforce_parameter_schema,
|
1051
1091
|
work_queue_name=work_queue_name,
|
1052
1092
|
job_variables=job_variables,
|
1093
|
+
entrypoint_type=entrypoint_type,
|
1053
1094
|
)
|
1054
1095
|
|
1055
1096
|
deployment_ids = await deploy(
|
@@ -1310,6 +1351,7 @@ def flow(
|
|
1310
1351
|
List[Callable[[FlowSchema, FlowRun, State], None]]
|
1311
1352
|
] = None,
|
1312
1353
|
on_crashed: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
1354
|
+
on_running: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
1313
1355
|
) -> Callable[[Callable[P, R]], Flow[P, R]]:
|
1314
1356
|
...
|
1315
1357
|
|
@@ -1337,6 +1379,7 @@ def flow(
|
|
1337
1379
|
List[Callable[[FlowSchema, FlowRun, State], None]]
|
1338
1380
|
] = None,
|
1339
1381
|
on_crashed: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
1382
|
+
on_running: Optional[List[Callable[[FlowSchema, FlowRun, State], None]]] = None,
|
1340
1383
|
):
|
1341
1384
|
"""
|
1342
1385
|
Decorator to designate a function as a Prefect workflow.
|
@@ -1400,6 +1443,8 @@ def flow(
|
|
1400
1443
|
on_crashed: An optional list of functions to call when the flow run crashes. Each
|
1401
1444
|
function should accept three arguments: the flow, the flow run, and the
|
1402
1445
|
final state of the flow run.
|
1446
|
+
on_running: An optional list of functions to call when the flow run is started. Each
|
1447
|
+
function should accept three arguments: the flow, the flow run, and the current state
|
1403
1448
|
|
1404
1449
|
Returns:
|
1405
1450
|
A callable `Flow` object which, when called, will run the flow and return its
|
@@ -1462,6 +1507,7 @@ def flow(
|
|
1462
1507
|
on_failure=on_failure,
|
1463
1508
|
on_cancellation=on_cancellation,
|
1464
1509
|
on_crashed=on_crashed,
|
1510
|
+
on_running=on_running,
|
1465
1511
|
),
|
1466
1512
|
)
|
1467
1513
|
else:
|
@@ -1487,6 +1533,7 @@ def flow(
|
|
1487
1533
|
on_failure=on_failure,
|
1488
1534
|
on_cancellation=on_cancellation,
|
1489
1535
|
on_crashed=on_crashed,
|
1536
|
+
on_running=on_running,
|
1490
1537
|
),
|
1491
1538
|
)
|
1492
1539
|
|
@@ -1585,7 +1632,8 @@ def load_flow_from_entrypoint(entrypoint: str) -> Flow:
|
|
1585
1632
|
Extract a flow object from a script at an entrypoint by running all of the code in the file.
|
1586
1633
|
|
1587
1634
|
Args:
|
1588
|
-
entrypoint: a string in the format `<path_to_script>:<flow_func_name>`
|
1635
|
+
entrypoint: a string in the format `<path_to_script>:<flow_func_name>` or a module path
|
1636
|
+
to a flow function
|
1589
1637
|
|
1590
1638
|
Returns:
|
1591
1639
|
The flow object from the script
|
@@ -1598,8 +1646,11 @@ def load_flow_from_entrypoint(entrypoint: str) -> Flow:
|
|
1598
1646
|
block_code_execution=True,
|
1599
1647
|
capture_failures=True,
|
1600
1648
|
):
|
1601
|
-
|
1602
|
-
|
1649
|
+
if ":" in entrypoint:
|
1650
|
+
# split by the last colon once to handle Windows paths with drive letters i.e C:\path\to\file.py:do_stuff
|
1651
|
+
path, func_name = entrypoint.rsplit(":", maxsplit=1)
|
1652
|
+
else:
|
1653
|
+
path, func_name = entrypoint.rsplit(".", maxsplit=1)
|
1603
1654
|
try:
|
1604
1655
|
flow = import_object(entrypoint)
|
1605
1656
|
except AttributeError as exc:
|
prefect/logging/filters.py
CHANGED
@@ -1,8 +1,31 @@
|
|
1
1
|
import logging
|
2
|
+
from typing import Any
|
2
3
|
|
4
|
+
from prefect.utilities.collections import visit_collection
|
3
5
|
from prefect.utilities.names import obfuscate
|
4
6
|
|
5
7
|
|
8
|
+
def redact_substr(obj: Any, substr: str):
|
9
|
+
"""
|
10
|
+
Redact a string from a potentially nested object.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
obj: The object to redact the string from
|
14
|
+
substr: The string to redact.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
Any: The object with the API key redacted.
|
18
|
+
"""
|
19
|
+
|
20
|
+
def redact_item(item):
|
21
|
+
if isinstance(item, str):
|
22
|
+
return item.replace(substr, obfuscate(substr))
|
23
|
+
return item
|
24
|
+
|
25
|
+
redacted_obj = visit_collection(obj, visit_fn=redact_item, return_data=True)
|
26
|
+
return redacted_obj
|
27
|
+
|
28
|
+
|
6
29
|
class ObfuscateApiKeyFilter(logging.Filter):
|
7
30
|
"""
|
8
31
|
A logging filter that obfuscates any string that matches the obfuscate_string function.
|
@@ -13,7 +36,6 @@ class ObfuscateApiKeyFilter(logging.Filter):
|
|
13
36
|
from prefect.settings import PREFECT_API_KEY
|
14
37
|
|
15
38
|
if PREFECT_API_KEY:
|
16
|
-
record.msg = record.msg.
|
17
|
-
|
18
|
-
)
|
39
|
+
record.msg = redact_substr(record.msg, PREFECT_API_KEY.value())
|
40
|
+
|
19
41
|
return True
|
prefect/results.py
CHANGED
@@ -4,6 +4,7 @@ from functools import partial
|
|
4
4
|
from typing import (
|
5
5
|
TYPE_CHECKING,
|
6
6
|
Any,
|
7
|
+
Awaitable,
|
7
8
|
Callable,
|
8
9
|
Dict,
|
9
10
|
Generic,
|
@@ -41,6 +42,7 @@ from prefect.settings import (
|
|
41
42
|
PREFECT_LOCAL_STORAGE_PATH,
|
42
43
|
PREFECT_RESULTS_DEFAULT_SERIALIZER,
|
43
44
|
PREFECT_RESULTS_PERSIST_BY_DEFAULT,
|
45
|
+
PREFECT_TASK_SCHEDULING_DEFAULT_STORAGE_BLOCK,
|
44
46
|
)
|
45
47
|
from prefect.utilities.annotations import NotSet
|
46
48
|
from prefect.utilities.asyncutils import sync_compatible
|
@@ -69,7 +71,6 @@ async def get_default_result_storage() -> ResultStorage:
|
|
69
71
|
"""
|
70
72
|
Generate a default file system for result storage.
|
71
73
|
"""
|
72
|
-
|
73
74
|
return (
|
74
75
|
await Block.load(PREFECT_DEFAULT_RESULT_STORAGE_BLOCK.value())
|
75
76
|
if PREFECT_DEFAULT_RESULT_STORAGE_BLOCK.value() is not None
|
@@ -77,6 +78,52 @@ async def get_default_result_storage() -> ResultStorage:
|
|
77
78
|
)
|
78
79
|
|
79
80
|
|
81
|
+
_default_task_scheduling_storages: Dict[Tuple[str, str], WritableFileSystem] = {}
|
82
|
+
|
83
|
+
|
84
|
+
async def get_or_create_default_task_scheduling_storage() -> ResultStorage:
|
85
|
+
"""
|
86
|
+
Generate a default file system for autonomous task parameter/result storage.
|
87
|
+
"""
|
88
|
+
default_storage_name, storage_path = cache_key = (
|
89
|
+
PREFECT_TASK_SCHEDULING_DEFAULT_STORAGE_BLOCK.value(),
|
90
|
+
PREFECT_LOCAL_STORAGE_PATH.value(),
|
91
|
+
)
|
92
|
+
|
93
|
+
async def get_storage():
|
94
|
+
try:
|
95
|
+
return await Block.load(default_storage_name)
|
96
|
+
except ValueError as e:
|
97
|
+
if "Unable to find" not in str(e):
|
98
|
+
raise e
|
99
|
+
|
100
|
+
block_type_slug, name = default_storage_name.split("/")
|
101
|
+
if block_type_slug == "local-file-system":
|
102
|
+
block = LocalFileSystem(basepath=storage_path)
|
103
|
+
else:
|
104
|
+
raise Exception(
|
105
|
+
"The default task storage block does not exist, but it is of type "
|
106
|
+
f"'{block_type_slug}' which cannot be created implicitly. Please create "
|
107
|
+
"the block manually."
|
108
|
+
)
|
109
|
+
|
110
|
+
try:
|
111
|
+
await block.save(name, overwrite=False)
|
112
|
+
return block
|
113
|
+
except ValueError as e:
|
114
|
+
if "already in use" not in str(e):
|
115
|
+
raise e
|
116
|
+
|
117
|
+
return await Block.load(default_storage_name)
|
118
|
+
|
119
|
+
try:
|
120
|
+
return _default_task_scheduling_storages[cache_key]
|
121
|
+
except KeyError:
|
122
|
+
storage = await get_storage()
|
123
|
+
_default_task_scheduling_storages[cache_key] = storage
|
124
|
+
return storage
|
125
|
+
|
126
|
+
|
80
127
|
def get_default_result_serializer() -> ResultSerializer:
|
81
128
|
"""
|
82
129
|
Generate a default file system for result storage.
|
@@ -231,10 +278,39 @@ class ResultFactory(pydantic.BaseModel):
|
|
231
278
|
|
232
279
|
ctx = FlowRunContext.get()
|
233
280
|
|
281
|
+
if ctx and ctx.autonomous_task_run:
|
282
|
+
return await cls.from_autonomous_task(task, client=client)
|
283
|
+
|
284
|
+
return await cls._from_task(task, get_default_result_storage, client=client)
|
285
|
+
|
286
|
+
@classmethod
|
287
|
+
@inject_client
|
288
|
+
async def from_autonomous_task(
|
289
|
+
cls: Type[Self], task: "Task", client: "PrefectClient" = None
|
290
|
+
) -> Self:
|
291
|
+
"""
|
292
|
+
Create a new result factory for an autonomous task.
|
293
|
+
"""
|
294
|
+
return await cls._from_task(
|
295
|
+
task, get_or_create_default_task_scheduling_storage, client=client
|
296
|
+
)
|
297
|
+
|
298
|
+
@classmethod
|
299
|
+
@inject_client
|
300
|
+
async def _from_task(
|
301
|
+
cls: Type[Self],
|
302
|
+
task: "Task",
|
303
|
+
default_storage_getter: Callable[[], Awaitable[ResultStorage]],
|
304
|
+
client: "PrefectClient" = None,
|
305
|
+
) -> Self:
|
306
|
+
from prefect.context import FlowRunContext
|
307
|
+
|
308
|
+
ctx = FlowRunContext.get()
|
309
|
+
|
234
310
|
result_storage = task.result_storage or (
|
235
311
|
ctx.result_factory.storage_block
|
236
312
|
if ctx and ctx.result_factory
|
237
|
-
else await
|
313
|
+
else await default_storage_getter()
|
238
314
|
)
|
239
315
|
result_serializer = task.result_serializer or (
|
240
316
|
ctx.result_factory.serializer
|
prefect/runner/runner.py
CHANGED
@@ -74,7 +74,11 @@ from prefect.client.schemas.objects import (
|
|
74
74
|
)
|
75
75
|
from prefect.client.schemas.schedules import SCHEDULE_TYPES
|
76
76
|
from prefect.deployments.deployments import load_flow_from_flow_run
|
77
|
-
from prefect.deployments.runner import
|
77
|
+
from prefect.deployments.runner import (
|
78
|
+
EntrypointType,
|
79
|
+
RunnerDeployment,
|
80
|
+
)
|
81
|
+
from prefect.deployments.schedules import FlexibleScheduleList
|
78
82
|
from prefect.engine import propose_state
|
79
83
|
from prefect.events.schemas import DeploymentTrigger
|
80
84
|
from prefect.exceptions import (
|
@@ -224,7 +228,7 @@ class Runner:
|
|
224
228
|
cron: Optional[Union[Iterable[str], str]] = None,
|
225
229
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
226
230
|
paused: Optional[bool] = None,
|
227
|
-
schedules: Optional[
|
231
|
+
schedules: Optional[FlexibleScheduleList] = None,
|
228
232
|
schedule: Optional[SCHEDULE_TYPES] = None,
|
229
233
|
is_schedule_active: Optional[bool] = None,
|
230
234
|
parameters: Optional[dict] = None,
|
@@ -233,6 +237,7 @@ class Runner:
|
|
233
237
|
tags: Optional[List[str]] = None,
|
234
238
|
version: Optional[str] = None,
|
235
239
|
enforce_parameter_schema: bool = False,
|
240
|
+
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
236
241
|
) -> UUID:
|
237
242
|
"""
|
238
243
|
Provides a flow to the runner to be run based on the provided configuration.
|
@@ -260,6 +265,8 @@ class Runner:
|
|
260
265
|
tags: A list of tags to associate with the created deployment for organizational
|
261
266
|
purposes.
|
262
267
|
version: A version for the created deployment. Defaults to the flow's version.
|
268
|
+
entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
|
269
|
+
entrypoint, ensure that the module will be importable in the execution environment.
|
263
270
|
"""
|
264
271
|
api = PREFECT_API_URL.value()
|
265
272
|
if any([interval, cron, rrule]) and not api:
|
@@ -284,6 +291,7 @@ class Runner:
|
|
284
291
|
tags=tags,
|
285
292
|
version=version,
|
286
293
|
enforce_parameter_schema=enforce_parameter_schema,
|
294
|
+
entrypoint_type=entrypoint_type,
|
287
295
|
)
|
288
296
|
return await self.add_deployment(deployment)
|
289
297
|
|
@@ -122,7 +122,8 @@
|
|
122
122
|
"auto_deregister_task_definition": "{{ auto_deregister_task_definition }}",
|
123
123
|
"vpc_id": "{{ vpc_id }}",
|
124
124
|
"container_name": "{{ container_name }}",
|
125
|
-
"cluster": "{{ cluster }}"
|
125
|
+
"cluster": "{{ cluster }}",
|
126
|
+
"match_latest_revision_in_family": "{{ match_latest_revision_in_family }}"
|
126
127
|
},
|
127
128
|
"variables": {
|
128
129
|
"description": "Variables for templating an ECS job.",
|
@@ -265,6 +266,12 @@
|
|
265
266
|
"description": "If enabled, any task definitions that are created by this block will be deregistered. Existing task definitions linked by ARN will never be deregistered. Deregistering a task definition does not remove it from your AWS account, instead it will be marked as INACTIVE.",
|
266
267
|
"default": false,
|
267
268
|
"type": "boolean"
|
269
|
+
},
|
270
|
+
"match_latest_revision_in_family": {
|
271
|
+
"title": "Match Latest Revision In Family",
|
272
|
+
"description": "If enabled, the most recent active revision in the task definition family will be compared against the desired ECS task configuration. If they are equal, the existing task definition will be used instead of registering a new one. If no family is specified the default family \"prefect\" will be used.",
|
273
|
+
"default": false,
|
274
|
+
"type": "boolean"
|
268
275
|
}
|
269
276
|
},
|
270
277
|
"definitions": {
|
@@ -1628,4 +1635,4 @@
|
|
1628
1635
|
"type": "kubernetes"
|
1629
1636
|
}
|
1630
1637
|
}
|
1631
|
-
}
|
1638
|
+
}
|
prefect/settings.py
CHANGED
@@ -102,6 +102,8 @@ T = TypeVar("T")
|
|
102
102
|
|
103
103
|
DEFAULT_PROFILES_PATH = Path(__file__).parent.joinpath("profiles.toml")
|
104
104
|
|
105
|
+
REMOVED_EXPERIMENTAL_FLAGS = {"PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_SCHEDULING_UI"}
|
106
|
+
|
105
107
|
|
106
108
|
class Setting(Generic[T]):
|
107
109
|
"""
|
@@ -600,6 +602,15 @@ If provided, the URL of a hosted Prefect API. Defaults to `None`.
|
|
600
602
|
When using Prefect Cloud, this will include an account and workspace.
|
601
603
|
"""
|
602
604
|
|
605
|
+
PREFECT_SILENCE_API_URL_MISCONFIGURATION = Setting(
|
606
|
+
bool,
|
607
|
+
default=False,
|
608
|
+
)
|
609
|
+
"""If `True`, disable the warning when a user accidentally misconfigure its `PREFECT_API_URL`
|
610
|
+
Sometimes when a user manually set `PREFECT_API_URL` to a custom url,reverse-proxy for example,
|
611
|
+
we would like to silence this warning so we will set it to `FALSE`.
|
612
|
+
"""
|
613
|
+
|
603
614
|
PREFECT_API_KEY = Setting(
|
604
615
|
str,
|
605
616
|
default=None,
|
@@ -1286,6 +1297,11 @@ PREFECT_EXPERIMENTAL_ENABLE_ARTIFACTS_ON_FLOW_RUN_GRAPH = Setting(bool, default=
|
|
1286
1297
|
Whether or not to enable artifacts on the flow run graph.
|
1287
1298
|
"""
|
1288
1299
|
|
1300
|
+
PREFECT_EXPERIMENTAL_ENABLE_STATES_ON_FLOW_RUN_GRAPH = Setting(bool, default=False)
|
1301
|
+
"""
|
1302
|
+
Whether or not to enable flow run states on the flow run graph.
|
1303
|
+
"""
|
1304
|
+
|
1289
1305
|
PREFECT_EXPERIMENTAL_ENABLE_EVENTS_CLIENT = Setting(bool, default=True)
|
1290
1306
|
"""
|
1291
1307
|
Whether or not to enable experimental Prefect work pools.
|
@@ -1326,6 +1342,11 @@ PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_CANCELLATION = Setting(bool, default=True)
|
|
1326
1342
|
Whether or not to enable experimental enhanced flow run cancellation.
|
1327
1343
|
"""
|
1328
1344
|
|
1345
|
+
PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_DEPLOYMENT_PARAMETERS = Setting(bool, default=True)
|
1346
|
+
"""
|
1347
|
+
Whether or not to enable enhanced deployment parameters.
|
1348
|
+
"""
|
1349
|
+
|
1329
1350
|
PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION = Setting(bool, default=False)
|
1330
1351
|
"""
|
1331
1352
|
Whether or not to warn when experimental enhanced flow run cancellation is used.
|
@@ -1417,6 +1438,14 @@ PREFECT_WORKER_WEBSERVER_PORT = Setting(
|
|
1417
1438
|
"""
|
1418
1439
|
The port the worker's webserver should bind to.
|
1419
1440
|
"""
|
1441
|
+
|
1442
|
+
PREFECT_TASK_SCHEDULING_DEFAULT_STORAGE_BLOCK = Setting(
|
1443
|
+
str,
|
1444
|
+
default="local-file-system/prefect-task-scheduling",
|
1445
|
+
)
|
1446
|
+
"""The `block-type/block-document` slug of a block to use as the default storage
|
1447
|
+
for autonomous tasks."""
|
1448
|
+
|
1420
1449
|
PREFECT_TASK_SCHEDULING_DELETE_FAILED_SUBMISSIONS = Setting(
|
1421
1450
|
bool,
|
1422
1451
|
default=True,
|
@@ -1441,6 +1470,16 @@ PREFECT_TASK_SCHEDULING_MAX_RETRY_QUEUE_SIZE = Setting(
|
|
1441
1470
|
The maximum number of retries to queue for submission.
|
1442
1471
|
"""
|
1443
1472
|
|
1473
|
+
PREFECT_TASK_SCHEDULING_PENDING_TASK_TIMEOUT = Setting(
|
1474
|
+
timedelta,
|
1475
|
+
default=timedelta(seconds=30),
|
1476
|
+
)
|
1477
|
+
"""
|
1478
|
+
How long before a PENDING task are made available to another task server. In practice,
|
1479
|
+
a task server should move a task from PENDING to RUNNING very quickly, so runs stuck in
|
1480
|
+
PENDING for a while is a sign that the task server may have crashed.
|
1481
|
+
"""
|
1482
|
+
|
1444
1483
|
PREFECT_EXPERIMENTAL_ENABLE_FLOW_RUN_INFRA_OVERRIDES = Setting(bool, default=False)
|
1445
1484
|
"""
|
1446
1485
|
Whether or not to enable infrastructure overrides made on flow runs.
|
@@ -1486,11 +1525,6 @@ PREFECT_EXPERIMENTAL_ENABLE_WORK_QUEUE_STATUS = Setting(bool, default=True)
|
|
1486
1525
|
Whether or not to enable experimental work queue status in-place of work queue health.
|
1487
1526
|
"""
|
1488
1527
|
|
1489
|
-
PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_SCHEDULING_UI = Setting(bool, default=True)
|
1490
|
-
"""
|
1491
|
-
Whether or not to enable the enhanced scheduling UI.
|
1492
|
-
"""
|
1493
|
-
|
1494
1528
|
|
1495
1529
|
# Defaults -----------------------------------------------------------------------------
|
1496
1530
|
|
@@ -1614,7 +1648,8 @@ class Settings(SettingsFieldsMixin):
|
|
1614
1648
|
# in the future.
|
1615
1649
|
values = max_log_size_smaller_than_batch_size(values)
|
1616
1650
|
values = warn_on_database_password_value_without_usage(values)
|
1617
|
-
|
1651
|
+
if not values["PREFECT_SILENCE_API_URL_MISCONFIGURATION"]:
|
1652
|
+
values = warn_on_misconfigured_api_url(values)
|
1618
1653
|
return values
|
1619
1654
|
|
1620
1655
|
def copy_with_update(
|
@@ -2043,6 +2078,24 @@ class ProfilesCollection:
|
|
2043
2078
|
)
|
2044
2079
|
|
2045
2080
|
|
2081
|
+
def _handle_removed_flags(profile_name: str, settings: dict) -> dict:
|
2082
|
+
to_remove = [name for name in settings if name in REMOVED_EXPERIMENTAL_FLAGS]
|
2083
|
+
|
2084
|
+
for name in to_remove:
|
2085
|
+
warnings.warn(
|
2086
|
+
(
|
2087
|
+
f"Experimental flag {name!r} has been removed, please "
|
2088
|
+
f"update your {profile_name!r} profile."
|
2089
|
+
),
|
2090
|
+
UserWarning,
|
2091
|
+
stacklevel=3,
|
2092
|
+
)
|
2093
|
+
|
2094
|
+
settings.pop(name)
|
2095
|
+
|
2096
|
+
return settings
|
2097
|
+
|
2098
|
+
|
2046
2099
|
def _read_profiles_from(path: Path) -> ProfilesCollection:
|
2047
2100
|
"""
|
2048
2101
|
Read profiles from a path into a new `ProfilesCollection`.
|
@@ -2059,10 +2112,10 @@ def _read_profiles_from(path: Path) -> ProfilesCollection:
|
|
2059
2112
|
active_profile = contents.get("active")
|
2060
2113
|
raw_profiles = contents.get("profiles", {})
|
2061
2114
|
|
2062
|
-
profiles = [
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2115
|
+
profiles = []
|
2116
|
+
for name, settings in raw_profiles.items():
|
2117
|
+
settings = _handle_removed_flags(name, settings)
|
2118
|
+
profiles.append(Profile(name=name, settings=settings, source=path))
|
2066
2119
|
|
2067
2120
|
return ProfilesCollection(profiles, active=active_profile)
|
2068
2121
|
|