prefect-client 3.0.0rc6__py3-none-any.whl → 3.0.0rc8__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 +75 -57
- prefect/_internal/compatibility/migration.py +2 -2
- prefect/client/orchestration.py +0 -3
- prefect/client/schemas/actions.py +0 -2
- prefect/client/schemas/objects.py +12 -8
- prefect/client/schemas/responses.py +0 -6
- prefect/flows.py +7 -11
- prefect/futures.py +73 -13
- prefect/main.py +70 -0
- prefect/plugins.py +1 -64
- prefect/results.py +14 -71
- prefect/runner/storage.py +75 -6
- prefect/settings.py +14 -138
- prefect/states.py +54 -5
- prefect/task_engine.py +10 -0
- prefect/task_runners.py +113 -7
- prefect/tasks.py +66 -26
- {prefect_client-3.0.0rc6.dist-info → prefect_client-3.0.0rc8.dist-info}/METADATA +1 -1
- {prefect_client-3.0.0rc6.dist-info → prefect_client-3.0.0rc8.dist-info}/RECORD +22 -21
- {prefect_client-3.0.0rc6.dist-info → prefect_client-3.0.0rc8.dist-info}/LICENSE +0 -0
- {prefect_client-3.0.0rc6.dist-info → prefect_client-3.0.0rc8.dist-info}/WHEEL +0 -0
- {prefect_client-3.0.0rc6.dist-info → prefect_client-3.0.0rc8.dist-info}/top_level.txt +0 -0
prefect/results.py
CHANGED
@@ -142,38 +142,6 @@ def get_default_persist_setting() -> bool:
|
|
142
142
|
return PREFECT_RESULTS_PERSIST_BY_DEFAULT.value()
|
143
143
|
|
144
144
|
|
145
|
-
def flow_features_require_result_persistence(flow: "Flow") -> bool:
|
146
|
-
"""
|
147
|
-
Returns `True` if the given flow uses features that require its result to be
|
148
|
-
persisted.
|
149
|
-
"""
|
150
|
-
if not flow.cache_result_in_memory:
|
151
|
-
return True
|
152
|
-
return False
|
153
|
-
|
154
|
-
|
155
|
-
def flow_features_require_child_result_persistence(flow: "Flow") -> bool:
|
156
|
-
"""
|
157
|
-
Returns `True` if the given flow uses features that require child flow and task
|
158
|
-
runs to persist their results.
|
159
|
-
"""
|
160
|
-
if flow and flow.retries:
|
161
|
-
return True
|
162
|
-
return False
|
163
|
-
|
164
|
-
|
165
|
-
def task_features_require_result_persistence(task: "Task") -> bool:
|
166
|
-
"""
|
167
|
-
Returns `True` if the given task uses features that require its result to be
|
168
|
-
persisted.
|
169
|
-
"""
|
170
|
-
if task.cache_key_fn:
|
171
|
-
return True
|
172
|
-
if not task.cache_result_in_memory:
|
173
|
-
return True
|
174
|
-
return False
|
175
|
-
|
176
|
-
|
177
145
|
def _format_user_supplied_storage_key(key: str) -> str:
|
178
146
|
# Note here we are pinning to task runs since flow runs do not support storage keys
|
179
147
|
# yet; we'll need to split logic in the future or have two separate functions
|
@@ -235,17 +203,7 @@ class ResultFactory(BaseModel):
|
|
235
203
|
result_storage=flow.result_storage or ctx.result_factory.storage_block,
|
236
204
|
result_serializer=flow.result_serializer
|
237
205
|
or ctx.result_factory.serializer,
|
238
|
-
persist_result=
|
239
|
-
flow.persist_result
|
240
|
-
if flow.persist_result is not None
|
241
|
-
# !! Child flows persist their result by default if the it or the
|
242
|
-
# parent flow uses a feature that requires it
|
243
|
-
else (
|
244
|
-
flow_features_require_result_persistence(flow)
|
245
|
-
or flow_features_require_child_result_persistence(ctx.flow)
|
246
|
-
or get_default_persist_setting()
|
247
|
-
)
|
248
|
-
),
|
206
|
+
persist_result=flow.persist_result,
|
249
207
|
cache_result_in_memory=flow.cache_result_in_memory,
|
250
208
|
storage_key_fn=DEFAULT_STORAGE_KEY_FN,
|
251
209
|
client=client,
|
@@ -258,16 +216,7 @@ class ResultFactory(BaseModel):
|
|
258
216
|
client=client,
|
259
217
|
result_storage=flow.result_storage,
|
260
218
|
result_serializer=flow.result_serializer,
|
261
|
-
persist_result=
|
262
|
-
flow.persist_result
|
263
|
-
if flow.persist_result is not None
|
264
|
-
# !! Flows persist their result by default if uses a feature that
|
265
|
-
# requires it
|
266
|
-
else (
|
267
|
-
flow_features_require_result_persistence(flow)
|
268
|
-
or get_default_persist_setting()
|
269
|
-
)
|
270
|
-
),
|
219
|
+
persist_result=flow.persist_result,
|
271
220
|
cache_result_in_memory=flow.cache_result_in_memory,
|
272
221
|
storage_key_fn=DEFAULT_STORAGE_KEY_FN,
|
273
222
|
)
|
@@ -318,21 +267,7 @@ class ResultFactory(BaseModel):
|
|
318
267
|
if ctx and ctx.result_factory
|
319
268
|
else get_default_result_serializer()
|
320
269
|
)
|
321
|
-
persist_result =
|
322
|
-
task.persist_result
|
323
|
-
if task.persist_result is not None
|
324
|
-
# !! Tasks persist their result by default if their parent flow uses a
|
325
|
-
# feature that requires it or the task uses a feature that requires it
|
326
|
-
else (
|
327
|
-
(
|
328
|
-
flow_features_require_child_result_persistence(ctx.flow)
|
329
|
-
if ctx
|
330
|
-
else False
|
331
|
-
)
|
332
|
-
or task_features_require_result_persistence(task)
|
333
|
-
or get_default_persist_setting()
|
334
|
-
)
|
335
|
-
)
|
270
|
+
persist_result = task.persist_result
|
336
271
|
|
337
272
|
cache_result_in_memory = task.cache_result_in_memory
|
338
273
|
|
@@ -355,11 +290,14 @@ class ResultFactory(BaseModel):
|
|
355
290
|
cls: Type[Self],
|
356
291
|
result_storage: ResultStorage,
|
357
292
|
result_serializer: ResultSerializer,
|
358
|
-
persist_result: bool,
|
293
|
+
persist_result: Optional[bool],
|
359
294
|
cache_result_in_memory: bool,
|
360
295
|
storage_key_fn: Callable[[], str],
|
361
296
|
client: "PrefectClient",
|
362
297
|
) -> Self:
|
298
|
+
if persist_result is None:
|
299
|
+
persist_result = get_default_persist_setting()
|
300
|
+
|
363
301
|
storage_block_id, storage_block = await cls.resolve_storage_block(
|
364
302
|
result_storage, client=client, persist_result=persist_result
|
365
303
|
)
|
@@ -614,7 +552,6 @@ class PersistedResult(BaseResult):
|
|
614
552
|
"""
|
615
553
|
Retrieve the data and deserialize it into the original object.
|
616
554
|
"""
|
617
|
-
|
618
555
|
if self.has_cached_object():
|
619
556
|
return self._cache
|
620
557
|
|
@@ -680,7 +617,13 @@ class PersistedResult(BaseResult):
|
|
680
617
|
# this could error if the serializer requires kwargs
|
681
618
|
serializer = Serializer(type=self.serializer_type)
|
682
619
|
|
683
|
-
|
620
|
+
try:
|
621
|
+
data = serializer.dumps(obj)
|
622
|
+
except Exception as exc:
|
623
|
+
raise ValueError(
|
624
|
+
f"Failed to serialize object of type {type(obj).__name__!r} with "
|
625
|
+
f"serializer {serializer.type!r}."
|
626
|
+
) from exc
|
684
627
|
blob = PersistedResultBlob(
|
685
628
|
serializer=serializer, data=data, expiration=self.expiration
|
686
629
|
)
|
prefect/runner/storage.py
CHANGED
@@ -559,8 +559,70 @@ class BlockStorageAdapter:
|
|
559
559
|
return False
|
560
560
|
|
561
561
|
|
562
|
-
|
563
|
-
|
562
|
+
class LocalStorage:
|
563
|
+
"""
|
564
|
+
Sets the working directory in the local filesystem.
|
565
|
+
Parameters:
|
566
|
+
Path: Local file path to set the working directory for the flow
|
567
|
+
Examples:
|
568
|
+
Sets the working directory for the local path to the flow:
|
569
|
+
```python
|
570
|
+
from prefect.runner.storage import Localstorage
|
571
|
+
storage = LocalStorage(
|
572
|
+
path="/path/to/local/flow_directory",
|
573
|
+
)
|
574
|
+
```
|
575
|
+
"""
|
576
|
+
|
577
|
+
def __init__(
|
578
|
+
self,
|
579
|
+
path: str,
|
580
|
+
pull_interval: Optional[int] = None,
|
581
|
+
):
|
582
|
+
self._path = Path(path).resolve()
|
583
|
+
self._logger = get_logger("runner.storage.local-storage")
|
584
|
+
self._storage_base_path = Path.cwd()
|
585
|
+
self._pull_interval = pull_interval
|
586
|
+
|
587
|
+
@property
|
588
|
+
def destination(self) -> Path:
|
589
|
+
return self._path
|
590
|
+
|
591
|
+
def set_base_path(self, path: Path):
|
592
|
+
self._storage_base_path = path
|
593
|
+
|
594
|
+
@property
|
595
|
+
def pull_interval(self) -> Optional[int]:
|
596
|
+
return self._pull_interval
|
597
|
+
|
598
|
+
async def pull_code(self):
|
599
|
+
# Local storage assumes the code already exists on the local filesystem
|
600
|
+
# and does not need to be pulled from a remote location
|
601
|
+
pass
|
602
|
+
|
603
|
+
def to_pull_step(self) -> dict:
|
604
|
+
"""
|
605
|
+
Returns a dictionary representation of the storage object that can be
|
606
|
+
used as a deployment pull step.
|
607
|
+
"""
|
608
|
+
step = {
|
609
|
+
"prefect.deployments.steps.set_working_directory": {
|
610
|
+
"directory": str(self.destination)
|
611
|
+
}
|
612
|
+
}
|
613
|
+
return step
|
614
|
+
|
615
|
+
def __eq__(self, __value) -> bool:
|
616
|
+
if isinstance(__value, LocalStorage):
|
617
|
+
return self._path == __value._path
|
618
|
+
return False
|
619
|
+
|
620
|
+
def __repr__(self) -> str:
|
621
|
+
return f"LocalStorage(path={self._path!r})"
|
622
|
+
|
623
|
+
|
624
|
+
def create_storage_from_source(
|
625
|
+
source: str, pull_interval: Optional[int] = 60
|
564
626
|
) -> RunnerStorage:
|
565
627
|
"""
|
566
628
|
Creates a storage object from a URL.
|
@@ -574,11 +636,18 @@ def create_storage_from_url(
|
|
574
636
|
Returns:
|
575
637
|
RunnerStorage: A runner storage compatible object
|
576
638
|
"""
|
577
|
-
|
578
|
-
|
579
|
-
|
639
|
+
logger = get_logger("runner.storage")
|
640
|
+
parsed_source = urlparse(source)
|
641
|
+
if parsed_source.scheme == "git" or parsed_source.path.endswith(".git"):
|
642
|
+
return GitRepository(url=source, pull_interval=pull_interval)
|
643
|
+
elif parsed_source.scheme in ("file", "local"):
|
644
|
+
source_path = source.split("://", 1)[-1]
|
645
|
+
return LocalStorage(path=source_path, pull_interval=pull_interval)
|
646
|
+
elif parsed_source.scheme in fsspec.available_protocols():
|
647
|
+
return RemoteStorage(url=source, pull_interval=pull_interval)
|
580
648
|
else:
|
581
|
-
|
649
|
+
logger.debug("No valid fsspec protocol found for URL, assuming local storage.")
|
650
|
+
return LocalStorage(path=source, pull_interval=pull_interval)
|
582
651
|
|
583
652
|
|
584
653
|
def _format_token_from_credentials(netloc: str, credentials: dict) -> str:
|
prefect/settings.py
CHANGED
@@ -92,21 +92,6 @@ T = TypeVar("T")
|
|
92
92
|
|
93
93
|
DEFAULT_PROFILES_PATH = Path(__file__).parent.joinpath("profiles.toml")
|
94
94
|
|
95
|
-
# When we remove the experimental settings we also want to add them to the set of REMOVED_EXPERIMENTAL_FLAGS.
|
96
|
-
# The reason for this is removing the settings entirely causes the CLI to crash for anyone who has them in one or more of their profiles.
|
97
|
-
# Adding them to REMOVED_EXPERIMENTAL_FLAGS will make it so that the user is warned about it and they have time to take action.
|
98
|
-
REMOVED_EXPERIMENTAL_FLAGS = {
|
99
|
-
"PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_SCHEDULING_UI",
|
100
|
-
"PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_DEPLOYMENT_PARAMETERS",
|
101
|
-
"PREFECT_EXPERIMENTAL_ENABLE_EVENTS_CLIENT",
|
102
|
-
"PREFECT_EXPERIMENTAL_ENABLE_EVENTS",
|
103
|
-
"PREFECT_EXPERIMENTAL_EVENTS",
|
104
|
-
"PREFECT_EXPERIMENTAL_WARN_EVENTS_CLIENT",
|
105
|
-
"PREFECT_EXPERIMENTAL_ENABLE_FLOW_RUN_INFRA_OVERRIDES",
|
106
|
-
"PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES",
|
107
|
-
"PREFECT_EXPERIMENTAL_ENABLE_WORK_POOLS",
|
108
|
-
}
|
109
|
-
|
110
95
|
|
111
96
|
class Setting(Generic[T]):
|
112
97
|
"""
|
@@ -423,7 +408,7 @@ def default_result_storage_block_name(
|
|
423
408
|
settings: Optional["Settings"] = None, value: Optional[str] = None
|
424
409
|
):
|
425
410
|
"""
|
426
|
-
`value_callback` for `
|
411
|
+
`value_callback` for `PREFECT_DEFAULT_RESULT_STORAGE_BLOCK` that sets the default
|
427
412
|
value to the hostname of the machine.
|
428
413
|
"""
|
429
414
|
if value is None:
|
@@ -749,7 +734,7 @@ PREFECT_RESULTS_DEFAULT_SERIALIZER = Setting(
|
|
749
734
|
|
750
735
|
PREFECT_RESULTS_PERSIST_BY_DEFAULT = Setting(
|
751
736
|
bool,
|
752
|
-
default=
|
737
|
+
default=True,
|
753
738
|
)
|
754
739
|
"""
|
755
740
|
The default setting for persisting results when not otherwise specified. If enabled,
|
@@ -959,41 +944,6 @@ interpreted and lead to incomplete output, e.g.
|
|
959
944
|
`DROP TABLE [dbo].[SomeTable];"` outputs `DROP TABLE .[SomeTable];`.
|
960
945
|
"""
|
961
946
|
|
962
|
-
PREFECT_TASK_INTROSPECTION_WARN_THRESHOLD = Setting(
|
963
|
-
float,
|
964
|
-
default=10.0,
|
965
|
-
)
|
966
|
-
"""
|
967
|
-
Threshold time in seconds for logging a warning if task parameter introspection
|
968
|
-
exceeds this duration. Parameter introspection can be a significant performance hit
|
969
|
-
when the parameter is a large collection object, e.g. a large dictionary or DataFrame,
|
970
|
-
and each element needs to be inspected. See `prefect.utilities.annotations.quote`
|
971
|
-
for more details.
|
972
|
-
Defaults to `10.0`.
|
973
|
-
Set to `0` to disable logging the warning.
|
974
|
-
"""
|
975
|
-
|
976
|
-
PREFECT_AGENT_QUERY_INTERVAL = Setting(
|
977
|
-
float,
|
978
|
-
default=15,
|
979
|
-
)
|
980
|
-
"""
|
981
|
-
The agent loop interval, in seconds. Agents will check for new runs this often.
|
982
|
-
Defaults to `15`.
|
983
|
-
"""
|
984
|
-
|
985
|
-
PREFECT_AGENT_PREFETCH_SECONDS = Setting(
|
986
|
-
int,
|
987
|
-
default=15,
|
988
|
-
)
|
989
|
-
"""
|
990
|
-
Agents will look for scheduled runs this many seconds in
|
991
|
-
the future and attempt to run them. This accounts for any additional
|
992
|
-
infrastructure spin-up time or latency in preparing a flow run. Note
|
993
|
-
flow runs will not start before their scheduled time, even if they are
|
994
|
-
prefetched. Defaults to `15`.
|
995
|
-
"""
|
996
|
-
|
997
947
|
PREFECT_ASYNC_FETCH_STATE_RESULT = Setting(bool, default=False)
|
998
948
|
"""
|
999
949
|
Determines whether `State.result()` fetches results automatically or not.
|
@@ -1373,16 +1323,6 @@ PREFECT_API_MAX_FLOW_RUN_GRAPH_ARTIFACTS = Setting(int, default=10000)
|
|
1373
1323
|
The maximum number of artifacts to show on a flow run graph on the v2 API
|
1374
1324
|
"""
|
1375
1325
|
|
1376
|
-
PREFECT_EXPERIMENTAL_ENABLE_ARTIFACTS_ON_FLOW_RUN_GRAPH = Setting(bool, default=True)
|
1377
|
-
"""
|
1378
|
-
Whether or not to enable artifacts on the flow run graph.
|
1379
|
-
"""
|
1380
|
-
|
1381
|
-
PREFECT_EXPERIMENTAL_ENABLE_STATES_ON_FLOW_RUN_GRAPH = Setting(bool, default=True)
|
1382
|
-
"""
|
1383
|
-
Whether or not to enable flow run states on the flow run graph.
|
1384
|
-
"""
|
1385
|
-
|
1386
1326
|
PREFECT_EXPERIMENTAL_ENABLE_WORKERS = Setting(bool, default=True)
|
1387
1327
|
"""
|
1388
1328
|
Whether or not to enable experimental Prefect workers.
|
@@ -1393,11 +1333,6 @@ PREFECT_EXPERIMENTAL_WARN_WORKERS = Setting(bool, default=False)
|
|
1393
1333
|
Whether or not to warn when experimental Prefect workers are used.
|
1394
1334
|
"""
|
1395
1335
|
|
1396
|
-
PREFECT_EXPERIMENTAL_WARN_VISUALIZE = Setting(bool, default=False)
|
1397
|
-
"""
|
1398
|
-
Whether or not to warn when experimental Prefect visualize is used.
|
1399
|
-
"""
|
1400
|
-
|
1401
1336
|
PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_CANCELLATION = Setting(bool, default=True)
|
1402
1337
|
"""
|
1403
1338
|
Whether or not to enable experimental enhanced flow run cancellation.
|
@@ -1408,26 +1343,6 @@ PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION = Setting(bool, default=False)
|
|
1408
1343
|
Whether or not to warn when experimental enhanced flow run cancellation is used.
|
1409
1344
|
"""
|
1410
1345
|
|
1411
|
-
PREFECT_EXPERIMENTAL_ENABLE_DEPLOYMENT_STATUS = Setting(bool, default=True)
|
1412
|
-
"""
|
1413
|
-
Whether or not to enable deployment status in the UI
|
1414
|
-
"""
|
1415
|
-
|
1416
|
-
PREFECT_EXPERIMENTAL_WARN_DEPLOYMENT_STATUS = Setting(bool, default=False)
|
1417
|
-
"""
|
1418
|
-
Whether or not to warn when deployment status is used.
|
1419
|
-
"""
|
1420
|
-
|
1421
|
-
PREFECT_EXPERIMENTAL_FLOW_RUN_INPUT = Setting(bool, default=False)
|
1422
|
-
"""
|
1423
|
-
Whether or not to enable flow run input.
|
1424
|
-
"""
|
1425
|
-
|
1426
|
-
PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INPUT = Setting(bool, default=True)
|
1427
|
-
"""
|
1428
|
-
Whether or not to enable flow run input.
|
1429
|
-
"""
|
1430
|
-
|
1431
1346
|
|
1432
1347
|
# Prefect Events feature flags
|
1433
1348
|
|
@@ -1554,31 +1469,6 @@ PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS = Setting(bool, default=False
|
|
1554
1469
|
Whether or not to enable experimental worker webserver endpoints.
|
1555
1470
|
"""
|
1556
1471
|
|
1557
|
-
PREFECT_EXPERIMENTAL_ENABLE_ARTIFACTS = Setting(bool, default=True)
|
1558
|
-
"""
|
1559
|
-
Whether or not to enable experimental Prefect artifacts.
|
1560
|
-
"""
|
1561
|
-
|
1562
|
-
PREFECT_EXPERIMENTAL_WARN_ARTIFACTS = Setting(bool, default=False)
|
1563
|
-
"""
|
1564
|
-
Whether or not to warn when experimental Prefect artifacts are used.
|
1565
|
-
"""
|
1566
|
-
|
1567
|
-
PREFECT_EXPERIMENTAL_ENABLE_WORKSPACE_DASHBOARD = Setting(bool, default=True)
|
1568
|
-
"""
|
1569
|
-
Whether or not to enable the experimental workspace dashboard.
|
1570
|
-
"""
|
1571
|
-
|
1572
|
-
PREFECT_EXPERIMENTAL_WARN_WORKSPACE_DASHBOARD = Setting(bool, default=False)
|
1573
|
-
"""
|
1574
|
-
Whether or not to warn when the experimental workspace dashboard is enabled.
|
1575
|
-
"""
|
1576
|
-
|
1577
|
-
PREFECT_EXPERIMENTAL_ENABLE_WORK_QUEUE_STATUS = Setting(bool, default=True)
|
1578
|
-
"""
|
1579
|
-
Whether or not to enable experimental work queue status in-place of work queue health.
|
1580
|
-
"""
|
1581
|
-
|
1582
1472
|
PREFECT_EXPERIMENTAL_DISABLE_SYNC_COMPAT = Setting(bool, default=False)
|
1583
1473
|
"""
|
1584
1474
|
Whether or not to disable the sync_compatible decorator utility.
|
@@ -1663,11 +1553,6 @@ PREFECT_EVENTS_MAXIMUM_SIZE_BYTES = Setting(int, default=1_500_000)
|
|
1663
1553
|
The maximum size of an Event when serialized to JSON
|
1664
1554
|
"""
|
1665
1555
|
|
1666
|
-
PREFECT_API_SERVICES_EVENT_LOGGER_ENABLED = Setting(bool, default=True)
|
1667
|
-
"""
|
1668
|
-
Whether or not to start the event debug logger service in the server application.
|
1669
|
-
"""
|
1670
|
-
|
1671
1556
|
PREFECT_API_SERVICES_TRIGGERS_ENABLED = Setting(bool, default=True)
|
1672
1557
|
"""
|
1673
1558
|
Whether or not to start the triggers service in the server application.
|
@@ -1715,6 +1600,18 @@ PREFECT_API_EVENTS_RELATED_RESOURCE_CACHE_TTL = Setting(
|
|
1715
1600
|
How long to cache related resource data for emitting server-side vents
|
1716
1601
|
"""
|
1717
1602
|
|
1603
|
+
PREFECT_EVENTS_MAXIMUM_WEBSOCKET_BACKFILL = Setting(
|
1604
|
+
timedelta, default=timedelta(minutes=15)
|
1605
|
+
)
|
1606
|
+
"""
|
1607
|
+
The maximum range to look back for backfilling events for a websocket subscriber
|
1608
|
+
"""
|
1609
|
+
|
1610
|
+
PREFECT_EVENTS_WEBSOCKET_BACKFILL_PAGE_SIZE = Setting(int, default=250, gt=0)
|
1611
|
+
"""
|
1612
|
+
The page size for the queries to backfill events for websocket subscribers
|
1613
|
+
"""
|
1614
|
+
|
1718
1615
|
|
1719
1616
|
# Deprecated settings ------------------------------------------------------------------
|
1720
1617
|
|
@@ -2215,26 +2112,6 @@ class ProfilesCollection:
|
|
2215
2112
|
)
|
2216
2113
|
|
2217
2114
|
|
2218
|
-
def _handle_removed_flags(
|
2219
|
-
profile_name: str, settings: Dict[str, Any]
|
2220
|
-
) -> Dict[str, Any]:
|
2221
|
-
to_remove = [name for name in settings if name in REMOVED_EXPERIMENTAL_FLAGS]
|
2222
|
-
|
2223
|
-
for name in to_remove:
|
2224
|
-
warnings.warn(
|
2225
|
-
(
|
2226
|
-
f"Experimental flag {name!r} has been removed, please "
|
2227
|
-
f"update your {profile_name!r} profile."
|
2228
|
-
),
|
2229
|
-
UserWarning,
|
2230
|
-
stacklevel=3,
|
2231
|
-
)
|
2232
|
-
|
2233
|
-
settings.pop(name)
|
2234
|
-
|
2235
|
-
return settings
|
2236
|
-
|
2237
|
-
|
2238
2115
|
def _read_profiles_from(path: Path) -> ProfilesCollection:
|
2239
2116
|
"""
|
2240
2117
|
Read profiles from a path into a new `ProfilesCollection`.
|
@@ -2253,7 +2130,6 @@ def _read_profiles_from(path: Path) -> ProfilesCollection:
|
|
2253
2130
|
|
2254
2131
|
profiles = []
|
2255
2132
|
for name, settings in raw_profiles.items():
|
2256
|
-
settings = _handle_removed_flags(name, settings)
|
2257
2133
|
profiles.append(Profile(name=name, settings=settings, source=path))
|
2258
2134
|
|
2259
2135
|
return ProfilesCollection(profiles, active=active_profile)
|
prefect/states.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import asyncio
|
1
2
|
import datetime
|
2
3
|
import sys
|
3
4
|
import traceback
|
@@ -22,15 +23,21 @@ from prefect.exceptions import (
|
|
22
23
|
TerminationSignal,
|
23
24
|
UnfinishedRun,
|
24
25
|
)
|
26
|
+
from prefect.logging.loggers import get_logger
|
25
27
|
from prefect.results import BaseResult, R, ResultFactory
|
26
28
|
from prefect.settings import PREFECT_ASYNC_FETCH_STATE_RESULT
|
27
29
|
from prefect.utilities.annotations import BaseAnnotation
|
28
30
|
from prefect.utilities.asyncutils import in_async_main_thread, sync_compatible
|
29
31
|
from prefect.utilities.collections import ensure_iterable
|
30
32
|
|
33
|
+
logger = get_logger("states")
|
34
|
+
|
31
35
|
|
32
36
|
def get_state_result(
|
33
|
-
state: State[R],
|
37
|
+
state: State[R],
|
38
|
+
raise_on_failure: bool = True,
|
39
|
+
fetch: Optional[bool] = None,
|
40
|
+
retry_result_failure: bool = True,
|
34
41
|
) -> R:
|
35
42
|
"""
|
36
43
|
Get the result from a state.
|
@@ -58,11 +65,50 @@ def get_state_result(
|
|
58
65
|
|
59
66
|
return state.data
|
60
67
|
else:
|
61
|
-
return _get_state_result(
|
68
|
+
return _get_state_result(
|
69
|
+
state,
|
70
|
+
raise_on_failure=raise_on_failure,
|
71
|
+
retry_result_failure=retry_result_failure,
|
72
|
+
)
|
73
|
+
|
74
|
+
|
75
|
+
RESULT_READ_MAXIMUM_ATTEMPTS = 10
|
76
|
+
RESULT_READ_RETRY_DELAY = 0.25
|
77
|
+
|
78
|
+
|
79
|
+
async def _get_state_result_data_with_retries(
|
80
|
+
state: State[R], retry_result_failure: bool = True
|
81
|
+
) -> R:
|
82
|
+
# Results may be written asynchronously, possibly after their corresponding
|
83
|
+
# state has been written and events have been emitted, so we should give some
|
84
|
+
# grace here about missing results. The exception below could come in the form
|
85
|
+
# of a missing file, a short read, or other types of errors depending on the
|
86
|
+
# result storage backend.
|
87
|
+
if retry_result_failure is False:
|
88
|
+
max_attempts = 1
|
89
|
+
else:
|
90
|
+
max_attempts = RESULT_READ_MAXIMUM_ATTEMPTS
|
91
|
+
|
92
|
+
for i in range(1, max_attempts + 1):
|
93
|
+
try:
|
94
|
+
return await state.data.get()
|
95
|
+
except Exception as e:
|
96
|
+
if i == max_attempts:
|
97
|
+
raise
|
98
|
+
logger.debug(
|
99
|
+
"Exception %r while reading result, retry %s/%s in %ss...",
|
100
|
+
e,
|
101
|
+
i,
|
102
|
+
max_attempts,
|
103
|
+
RESULT_READ_RETRY_DELAY,
|
104
|
+
)
|
105
|
+
await asyncio.sleep(RESULT_READ_RETRY_DELAY)
|
62
106
|
|
63
107
|
|
64
108
|
@sync_compatible
|
65
|
-
async def _get_state_result(
|
109
|
+
async def _get_state_result(
|
110
|
+
state: State[R], raise_on_failure: bool, retry_result_failure: bool = True
|
111
|
+
) -> R:
|
66
112
|
"""
|
67
113
|
Internal implementation for `get_state_result` without async backwards compatibility
|
68
114
|
"""
|
@@ -81,7 +127,10 @@ async def _get_state_result(state: State[R], raise_on_failure: bool) -> R:
|
|
81
127
|
raise await get_state_exception(state)
|
82
128
|
|
83
129
|
if isinstance(state.data, BaseResult):
|
84
|
-
result = await
|
130
|
+
result = await _get_state_result_data_with_retries(
|
131
|
+
state, retry_result_failure=retry_result_failure
|
132
|
+
)
|
133
|
+
|
85
134
|
elif state.data is None:
|
86
135
|
if state.is_failed() or state.is_crashed() or state.is_cancelled():
|
87
136
|
return await get_state_exception(state)
|
@@ -352,7 +401,7 @@ async def get_state_exception(state: State) -> BaseException:
|
|
352
401
|
raise ValueError(f"Expected failed or crashed state got {state!r}.")
|
353
402
|
|
354
403
|
if isinstance(state.data, BaseResult):
|
355
|
-
result = await state
|
404
|
+
result = await _get_state_result_data_with_retries(state)
|
356
405
|
elif state.data is None:
|
357
406
|
result = None
|
358
407
|
else:
|
prefect/task_engine.py
CHANGED
@@ -249,6 +249,16 @@ class TaskRunEngine(Generic[P, R]):
|
|
249
249
|
new_state = Running()
|
250
250
|
state = self.set_state(new_state)
|
251
251
|
|
252
|
+
# TODO: this is temporary until the API stops rejecting state transitions
|
253
|
+
# and the client / transaction store becomes the source of truth
|
254
|
+
# this is a bandaid caused by the API storing a Completed state with a bad
|
255
|
+
# result reference that no longer exists
|
256
|
+
if state.is_completed():
|
257
|
+
try:
|
258
|
+
state.result(retry_result_failure=False, _sync=True)
|
259
|
+
except Exception:
|
260
|
+
state = self.set_state(new_state, force=True)
|
261
|
+
|
252
262
|
BACKOFF_MAX = 10
|
253
263
|
backoff_count = 0
|
254
264
|
|