prefect 3.9.2.dev5__py3-none-any.whl → 3.9.2.dev6__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/_build_info.py +3 -3
- prefect/flow_engine.py +48 -20
- {prefect-3.9.2.dev5.dist-info → prefect-3.9.2.dev6.dist-info}/METADATA +1 -1
- {prefect-3.9.2.dev5.dist-info → prefect-3.9.2.dev6.dist-info}/RECORD +7 -7
- {prefect-3.9.2.dev5.dist-info → prefect-3.9.2.dev6.dist-info}/WHEEL +0 -0
- {prefect-3.9.2.dev5.dist-info → prefect-3.9.2.dev6.dist-info}/entry_points.txt +0 -0
- {prefect-3.9.2.dev5.dist-info → prefect-3.9.2.dev6.dist-info}/licenses/LICENSE +0 -0
prefect/_build_info.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Generated by versioningit
|
|
2
|
-
__version__ = "3.9.2.
|
|
3
|
-
__build_date__ = "2026-11-
|
|
4
|
-
__git_commit__ = "
|
|
2
|
+
__version__ = "3.9.2.dev6"
|
|
3
|
+
__build_date__ = "2026-11-06 08:14:36.397592+00:00"
|
|
4
|
+
__git_commit__ = "802fc9435423bed0d16fe30862de25a8df62493f"
|
|
5
5
|
__dirty__ = False
|
prefect/flow_engine.py
CHANGED
|
@@ -11,7 +11,7 @@ import signal
|
|
|
11
11
|
import sys
|
|
12
12
|
import threading
|
|
13
13
|
import time
|
|
14
|
-
from collections.abc import Mapping
|
|
14
|
+
from collections.abc import Callable, Mapping
|
|
15
15
|
from contextlib import (
|
|
16
16
|
AsyncExitStack,
|
|
17
17
|
ExitStack,
|
|
@@ -334,28 +334,40 @@ def _send_heartbeats(
|
|
|
334
334
|
resource, related = engine._build_heartbeat_event_template()
|
|
335
335
|
|
|
336
336
|
stop_event = threading.Event()
|
|
337
|
+
# The heartbeat thread checks for a stop and emits while holding this lock,
|
|
338
|
+
# so once `stop_heartbeats` returns, no heartbeat is mid-emit and none will
|
|
339
|
+
# be emitted.
|
|
340
|
+
emit_lock = threading.Lock()
|
|
337
341
|
|
|
338
|
-
def
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (
|
|
342
|
-
engine.flow_run
|
|
343
|
-
and engine.flow_run.state
|
|
344
|
-
and engine.flow_run.state.is_final()
|
|
345
|
-
):
|
|
346
|
-
engine.logger.debug("Flow run in terminal state, stopping heartbeat")
|
|
347
|
-
return
|
|
348
|
-
|
|
349
|
-
try:
|
|
350
|
-
engine._emit_flow_run_heartbeat(resource, related)
|
|
351
|
-
except Exception:
|
|
352
|
-
engine.logger.debug("Failed to emit heartbeat", exc_info=True)
|
|
342
|
+
def stop_heartbeats() -> None:
|
|
343
|
+
with emit_lock:
|
|
344
|
+
stop_event.set()
|
|
353
345
|
|
|
354
|
-
|
|
355
|
-
|
|
346
|
+
def heartbeat_loop() -> None:
|
|
347
|
+
while True:
|
|
348
|
+
with emit_lock:
|
|
356
349
|
if stop_event.is_set():
|
|
357
350
|
return
|
|
358
|
-
|
|
351
|
+
|
|
352
|
+
# Check state before emitting - don't emit if final
|
|
353
|
+
if (
|
|
354
|
+
engine.flow_run
|
|
355
|
+
and engine.flow_run.state
|
|
356
|
+
and engine.flow_run.state.is_final()
|
|
357
|
+
):
|
|
358
|
+
engine.logger.debug(
|
|
359
|
+
"Flow run in terminal state, stopping heartbeat"
|
|
360
|
+
)
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
engine._emit_flow_run_heartbeat(resource, related)
|
|
365
|
+
except Exception:
|
|
366
|
+
engine.logger.debug("Failed to emit heartbeat", exc_info=True)
|
|
367
|
+
|
|
368
|
+
# Waiting on the event wakes the thread as soon as heartbeats stop
|
|
369
|
+
if stop_event.wait(heartbeat_seconds):
|
|
370
|
+
return
|
|
359
371
|
|
|
360
372
|
# Copy the current context so the heartbeat thread sees the same
|
|
361
373
|
# `SettingsContext` (and therefore the same `PREFECT_API_URL`) as the
|
|
@@ -370,13 +382,14 @@ def _send_heartbeats(
|
|
|
370
382
|
thread = threading.Thread(
|
|
371
383
|
target=heartbeat_ctx.run, args=(heartbeat_loop,), daemon=True
|
|
372
384
|
)
|
|
385
|
+
engine._stop_heartbeats = stop_heartbeats
|
|
373
386
|
thread.start()
|
|
374
387
|
engine.logger.debug("Started flow run heartbeat context")
|
|
375
388
|
|
|
376
389
|
try:
|
|
377
390
|
yield
|
|
378
391
|
finally:
|
|
379
|
-
|
|
392
|
+
stop_heartbeats()
|
|
380
393
|
if join_on_exit:
|
|
381
394
|
thread.join(timeout=2)
|
|
382
395
|
engine.logger.debug("Stopped flow run heartbeat context")
|
|
@@ -428,6 +441,15 @@ class BaseFlowRunEngine(Generic[P, R]):
|
|
|
428
441
|
default_factory=FlowRunSuspensionRequest
|
|
429
442
|
)
|
|
430
443
|
_attempt_conclusion: EngineOutcomeReceipt | None = field(default=None, init=False)
|
|
444
|
+
# Stops the heartbeat thread started by the most recent `_send_heartbeats`.
|
|
445
|
+
# `set_state` calls it before proposing a terminal state: the server
|
|
446
|
+
# timestamps that state when it accepts it, but the heartbeat thread sees
|
|
447
|
+
# it only after the response arrives. A heartbeat sent in that gap occurs
|
|
448
|
+
# after the terminal state, and an automation that expects every heartbeat
|
|
449
|
+
# to be followed by another event then fires on the finished run.
|
|
450
|
+
_stop_heartbeats: Callable[[], None] | None = field(
|
|
451
|
+
default=None, init=False, repr=False
|
|
452
|
+
)
|
|
431
453
|
|
|
432
454
|
def __post_init__(self) -> None:
|
|
433
455
|
if self.flow is None and self.flow_run_id is None:
|
|
@@ -761,6 +783,9 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
761
783
|
if self.short_circuit:
|
|
762
784
|
return self.state
|
|
763
785
|
|
|
786
|
+
if state.is_final() and self._stop_heartbeats is not None:
|
|
787
|
+
self._stop_heartbeats()
|
|
788
|
+
|
|
764
789
|
state = propose_state_sync(
|
|
765
790
|
self.client, state, flow_run_id=self.flow_run.id, force=force
|
|
766
791
|
) # type: ignore
|
|
@@ -1500,6 +1525,9 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
|
1500
1525
|
if self.short_circuit:
|
|
1501
1526
|
return self.state
|
|
1502
1527
|
|
|
1528
|
+
if state.is_final() and self._stop_heartbeats is not None:
|
|
1529
|
+
self._stop_heartbeats()
|
|
1530
|
+
|
|
1503
1531
|
state = await propose_state(
|
|
1504
1532
|
self.client, state, flow_run_id=self.flow_run.id, force=force
|
|
1505
1533
|
) # type: ignore
|
|
@@ -2,7 +2,7 @@ prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
|
|
2
2
|
prefect/AGENTS.md,sha256=BI3DGSwZTEHIg_d3pwt2tGx659DXCUi9HgjpHhnfJRY,14281
|
|
3
3
|
prefect/__init__.py,sha256=FtzUynR70uuE9WgVABo7cZkGGeNdL8Q1gJVTtmqvpyg,6772
|
|
4
4
|
prefect/__main__.py,sha256=WFjw3kaYJY6pOTA7WDOgqjsz8zUEUZHCcj3P5wyVa-g,66
|
|
5
|
-
prefect/_build_info.py,sha256=
|
|
5
|
+
prefect/_build_info.py,sha256=IhZ_c3TJ-QIk6XHxP0n_7qUKMiJ2CO28iMufduaxXTY,185
|
|
6
6
|
prefect/_flow_run_suspension.py,sha256=5zTTB7ZIBHzoS0pVrhNn23-9hK51qZ3CQA6C-azluC0,4144
|
|
7
7
|
prefect/agent.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
|
8
8
|
prefect/artifacts.py,sha256=ydlAad-FUepGUvTzmDkSmZLFRdMHohqVhwKnufJkeOw,23955
|
|
@@ -12,7 +12,7 @@ prefect/context.py,sha256=0jvq1dacNBpEwm_t5GQC2ngg1yI7OYcHpIx_ap_j9t4,39646
|
|
|
12
12
|
prefect/engine.py,sha256=uM2-08TDIPf9RILKrg0Hzc9zuhCbtPDo9CQjKw_1c-s,6301
|
|
13
13
|
prefect/exceptions.py,sha256=MRWzDG8zVzl9cep90bfFS1JEAR3CXoXDyy7qaxWPnLg,12727
|
|
14
14
|
prefect/filesystems.py,sha256=eCgfNECSwlaqB_9UEHt8RgeHZBsa54Jmq0mlVXH_oeg,28900
|
|
15
|
-
prefect/flow_engine.py,sha256=
|
|
15
|
+
prefect/flow_engine.py,sha256=PdnlnJf1uMWB6QUhNjZ9rzMVR1-gI978BgckgbmRsCk,94824
|
|
16
16
|
prefect/flow_runs.py,sha256=heh7pdxDBNPU_uSa3zczJRoXra7t600AoAcBZFBdP28,30670
|
|
17
17
|
prefect/flows.py,sha256=L9I26RDn5R6DpwRquYtYYSTEl_QM-DD9cL_po4iMBmc,150053
|
|
18
18
|
prefect/futures.py,sha256=sbtEOrwyegEmIWjEHanidV-IcYICgrodHF8tSOmydLI,33343
|
|
@@ -1240,8 +1240,8 @@ prefect/workers/_worker_channel/_protocol.py,sha256=GpCNh1o3qmmqHA_UOOTge1QVC6IR
|
|
|
1240
1240
|
prefect/workers/_worker_channel/_state.py,sha256=eQTFZtAVDZH1vVWps3SdeY6aW3qu2wx1UKYQXK3AyuE,5369
|
|
1241
1241
|
prefect/workers/_worker_channel/_sync.py,sha256=G5G8_UaQYbeLebi5Mb1Z_KgGfXfyjXo5uT9la5_zwqY,14984
|
|
1242
1242
|
prefect/workers/_worker_channel/_transport.py,sha256=6VXxiZKIu0rqImlif14ojoAL3UGOBTmNpnlYxNggaLE,9423
|
|
1243
|
-
prefect-3.9.2.
|
|
1244
|
-
prefect-3.9.2.
|
|
1245
|
-
prefect-3.9.2.
|
|
1246
|
-
prefect-3.9.2.
|
|
1247
|
-
prefect-3.9.2.
|
|
1243
|
+
prefect-3.9.2.dev6.dist-info/METADATA,sha256=g_ByggJVO9wKEr5ZFH9BTAaQKm6hfamhgCyELtaU8cc,14407
|
|
1244
|
+
prefect-3.9.2.dev6.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
1245
|
+
prefect-3.9.2.dev6.dist-info/entry_points.txt,sha256=HlY8up83iIq2vU2r33a0qSis4eOFSyb1mRH4l7Xt9X8,126
|
|
1246
|
+
prefect-3.9.2.dev6.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
|
1247
|
+
prefect-3.9.2.dev6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|