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/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
- data = serializer.dumps(obj)
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
- def create_storage_from_url(
563
- url: str, pull_interval: Optional[int] = 60
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
- parsed_url = urlparse(url)
578
- if parsed_url.scheme == "git" or parsed_url.path.endswith(".git"):
579
- return GitRepository(url=url, pull_interval=pull_interval)
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
- return RemoteStorage(url=url, pull_interval=pull_interval)
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 `PREFECT_DEFAULT_RESULT_STORAGE_BLOCK_NAME` that sets the default
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=False,
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], raise_on_failure: bool = True, fetch: Optional[bool] = None
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(state, raise_on_failure=raise_on_failure)
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(state: State[R], raise_on_failure: bool) -> R:
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 state.data.get()
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.data.get()
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