prefect-client 3.4.0__py3-none-any.whl → 3.4.1.dev2__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/client/orchestration/__init__.py +16 -8
- prefect/client/subscriptions.py +18 -9
- prefect/events/clients.py +2 -2
- prefect/runner/_observers.py +60 -0
- prefect/runner/runner.py +47 -197
- prefect/tasks.py +1 -1
- {prefect_client-3.4.0.dist-info → prefect_client-3.4.1.dev2.dist-info}/METADATA +1 -1
- {prefect_client-3.4.0.dist-info → prefect_client-3.4.1.dev2.dist-info}/RECORD +11 -10
- {prefect_client-3.4.0.dist-info → prefect_client-3.4.1.dev2.dist-info}/WHEEL +0 -0
- {prefect_client-3.4.0.dist-info → prefect_client-3.4.1.dev2.dist-info}/licenses/LICENSE +0 -0
prefect/_build_info.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Generated by versioningit
|
2
|
-
__version__ = "3.4.
|
3
|
-
__build_date__ = "2025-05-
|
4
|
-
__git_commit__ = "
|
2
|
+
__version__ = "3.4.1.dev2"
|
3
|
+
__build_date__ = "2025-05-05 08:08:58.760597+00:00"
|
4
|
+
__git_commit__ = "c158d3eb6aae366fd814ba55c9151ca73ca1666a"
|
5
5
|
__dirty__ = False
|
@@ -322,12 +322,16 @@ class PrefectClient(
|
|
322
322
|
if api_version is None:
|
323
323
|
api_version = SERVER_API_VERSION
|
324
324
|
httpx_settings["headers"].setdefault("X-PREFECT-API-VERSION", api_version)
|
325
|
-
if api_key
|
326
|
-
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
327
|
-
|
325
|
+
# Prioritize auth_string if provided, otherwise use api_key
|
328
326
|
if auth_string:
|
329
327
|
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
330
|
-
httpx_settings["headers"]
|
328
|
+
httpx_settings["headers"]["Authorization"] = (
|
329
|
+
f"Basic {token}" # Overwrite if exists
|
330
|
+
)
|
331
|
+
elif api_key:
|
332
|
+
httpx_settings["headers"]["Authorization"] = (
|
333
|
+
f"Bearer {api_key}" # Set if auth_string is not present
|
334
|
+
)
|
331
335
|
|
332
336
|
# Context management
|
333
337
|
self._context_stack: int = 0
|
@@ -1189,12 +1193,16 @@ class SyncPrefectClient(
|
|
1189
1193
|
if api_version is None:
|
1190
1194
|
api_version = SERVER_API_VERSION
|
1191
1195
|
httpx_settings["headers"].setdefault("X-PREFECT-API-VERSION", api_version)
|
1192
|
-
if api_key
|
1193
|
-
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
1194
|
-
|
1196
|
+
# Prioritize auth_string if provided, otherwise use api_key
|
1195
1197
|
if auth_string:
|
1196
1198
|
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
1197
|
-
httpx_settings["headers"]
|
1199
|
+
httpx_settings["headers"]["Authorization"] = (
|
1200
|
+
f"Basic {token}" # Overwrite if exists
|
1201
|
+
)
|
1202
|
+
elif api_key:
|
1203
|
+
httpx_settings["headers"]["Authorization"] = (
|
1204
|
+
f"Bearer {api_key}" # Set if auth_string is not present
|
1205
|
+
)
|
1198
1206
|
|
1199
1207
|
# Context management
|
1200
1208
|
self._context_stack: int = 0
|
prefect/client/subscriptions.py
CHANGED
@@ -13,7 +13,7 @@ from typing_extensions import Self
|
|
13
13
|
from prefect._internal.schemas.bases import IDBaseModel
|
14
14
|
from prefect.events.clients import websocket_connect
|
15
15
|
from prefect.logging import get_logger
|
16
|
-
from prefect.settings import
|
16
|
+
from prefect.settings import get_current_settings
|
17
17
|
|
18
18
|
logger: Logger = get_logger(__name__)
|
19
19
|
|
@@ -76,10 +76,17 @@ class Subscription(Generic[S]):
|
|
76
76
|
websocket = await self._connect.__aenter__()
|
77
77
|
|
78
78
|
try:
|
79
|
+
settings = get_current_settings()
|
80
|
+
auth_token = (
|
81
|
+
settings.api.auth_string.get_secret_value()
|
82
|
+
if settings.api.auth_string
|
83
|
+
else None
|
84
|
+
)
|
85
|
+
api_key = settings.api.key.get_secret_value() if settings.api.key else None
|
86
|
+
token = auth_token or api_key # Prioritize auth_token
|
87
|
+
|
79
88
|
await websocket.send(
|
80
|
-
orjson.dumps(
|
81
|
-
{"type": "auth", "token": PREFECT_API_KEY.value()}
|
82
|
-
).decode()
|
89
|
+
orjson.dumps({"type": "auth", "token": token}).decode()
|
83
90
|
)
|
84
91
|
|
85
92
|
auth: dict[str, Any] = orjson.loads(await websocket.recv())
|
@@ -107,11 +114,13 @@ class Subscription(Generic[S]):
|
|
107
114
|
reason = None
|
108
115
|
|
109
116
|
if reason:
|
110
|
-
|
111
|
-
"Unable to authenticate to the subscription. Please "
|
112
|
-
"
|
113
|
-
|
114
|
-
|
117
|
+
error_message = (
|
118
|
+
"Unable to authenticate to the subscription. Please ensure the provided "
|
119
|
+
"`PREFECT_API_AUTH_STRING` (for self-hosted with auth string) or "
|
120
|
+
"`PREFECT_API_KEY` (for Cloud or self-hosted with API key) "
|
121
|
+
f"you are using is valid for this environment. Reason: {reason}"
|
122
|
+
)
|
123
|
+
raise Exception(error_message) from e
|
115
124
|
raise
|
116
125
|
else:
|
117
126
|
self._websocket = websocket
|
prefect/events/clients.py
CHANGED
@@ -684,8 +684,8 @@ class PrefectEventSubscriber:
|
|
684
684
|
|
685
685
|
async def __aexit__(
|
686
686
|
self,
|
687
|
-
exc_type: Optional[Type[
|
688
|
-
exc_val: Optional[
|
687
|
+
exc_type: Optional[Type[BaseException]],
|
688
|
+
exc_val: Optional[BaseException],
|
689
689
|
exc_tb: Optional[TracebackType],
|
690
690
|
) -> None:
|
691
691
|
self._websocket = None
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import asyncio
|
2
|
+
import uuid
|
3
|
+
from contextlib import AsyncExitStack
|
4
|
+
from typing import Any, Protocol
|
5
|
+
|
6
|
+
from prefect.events.clients import PrefectEventSubscriber, get_events_subscriber
|
7
|
+
from prefect.events.filters import EventFilter, EventNameFilter
|
8
|
+
from prefect.logging.loggers import get_logger
|
9
|
+
|
10
|
+
|
11
|
+
class OnCancellingCallback(Protocol):
|
12
|
+
def __call__(self, flow_run_id: uuid.UUID) -> None: ...
|
13
|
+
|
14
|
+
|
15
|
+
class FlowRunCancellingObserver:
|
16
|
+
def __init__(self, on_cancelling: OnCancellingCallback):
|
17
|
+
self.logger = get_logger("FlowRunCancellingObserver")
|
18
|
+
self.on_cancelling = on_cancelling
|
19
|
+
self._events_subscriber: PrefectEventSubscriber | None
|
20
|
+
self._exit_stack = AsyncExitStack()
|
21
|
+
|
22
|
+
async def _consume_events(self):
|
23
|
+
if self._events_subscriber is None:
|
24
|
+
raise RuntimeError(
|
25
|
+
"Events subscriber not initialized. Please use `async with` to initialize the observer."
|
26
|
+
)
|
27
|
+
async for event in self._events_subscriber:
|
28
|
+
try:
|
29
|
+
flow_run_id = uuid.UUID(
|
30
|
+
event.resource["prefect.resource.id"].replace(
|
31
|
+
"prefect.flow-run.", ""
|
32
|
+
)
|
33
|
+
)
|
34
|
+
self.on_cancelling(flow_run_id)
|
35
|
+
except ValueError:
|
36
|
+
self.logger.debug(
|
37
|
+
"Received event with invalid flow run ID: %s",
|
38
|
+
event.resource["prefect.resource.id"],
|
39
|
+
)
|
40
|
+
|
41
|
+
async def __aenter__(self):
|
42
|
+
self._events_subscriber = await self._exit_stack.enter_async_context(
|
43
|
+
get_events_subscriber(
|
44
|
+
filter=EventFilter(
|
45
|
+
event=EventNameFilter(name=["prefect.flow-run.Cancelling"])
|
46
|
+
)
|
47
|
+
)
|
48
|
+
)
|
49
|
+
self._consumer_task = asyncio.create_task(self._consume_events())
|
50
|
+
return self
|
51
|
+
|
52
|
+
async def __aexit__(self, *exc_info: Any):
|
53
|
+
await self._exit_stack.__aexit__(*exc_info)
|
54
|
+
self._consumer_task.cancel()
|
55
|
+
try:
|
56
|
+
await self._consumer_task
|
57
|
+
except asyncio.CancelledError:
|
58
|
+
pass
|
59
|
+
except Exception:
|
60
|
+
self.logger.exception("Error consuming events")
|
prefect/runner/runner.py
CHANGED
@@ -46,6 +46,8 @@ import subprocess
|
|
46
46
|
import sys
|
47
47
|
import tempfile
|
48
48
|
import threading
|
49
|
+
import uuid
|
50
|
+
from contextlib import AsyncExitStack
|
49
51
|
from copy import deepcopy
|
50
52
|
from functools import partial
|
51
53
|
from pathlib import Path
|
@@ -80,13 +82,6 @@ from prefect._internal.concurrency.api import (
|
|
80
82
|
from_sync,
|
81
83
|
)
|
82
84
|
from prefect.client.orchestration import PrefectClient, get_client
|
83
|
-
from prefect.client.schemas.filters import (
|
84
|
-
FlowRunFilter,
|
85
|
-
FlowRunFilterId,
|
86
|
-
FlowRunFilterState,
|
87
|
-
FlowRunFilterStateName,
|
88
|
-
FlowRunFilterStateType,
|
89
|
-
)
|
90
85
|
from prefect.client.schemas.objects import (
|
91
86
|
ConcurrencyLimitConfig,
|
92
87
|
State,
|
@@ -100,6 +95,7 @@ from prefect.events.utilities import emit_event
|
|
100
95
|
from prefect.exceptions import Abort, ObjectNotFound
|
101
96
|
from prefect.flows import Flow, FlowStateHook, load_flow_from_flow_run
|
102
97
|
from prefect.logging.loggers import PrefectLogAdapter, flow_run_logger, get_logger
|
98
|
+
from prefect.runner._observers import FlowRunCancellingObserver
|
103
99
|
from prefect.runner.storage import RunnerStorage
|
104
100
|
from prefect.schedules import Schedule
|
105
101
|
from prefect.settings import (
|
@@ -229,6 +225,7 @@ class Runner:
|
|
229
225
|
raise ValueError("Heartbeat must be 30 seconds or greater.")
|
230
226
|
self._heartbeat_task: asyncio.Task[None] | None = None
|
231
227
|
|
228
|
+
self._exit_stack = AsyncExitStack()
|
232
229
|
self._limiter: anyio.CapacityLimiter | None = None
|
233
230
|
self._client: PrefectClient = get_client()
|
234
231
|
self._submitting_flow_run_ids: set[UUID] = set()
|
@@ -501,15 +498,6 @@ class Runner:
|
|
501
498
|
jitter_range=0.3,
|
502
499
|
)
|
503
500
|
)
|
504
|
-
loops_task_group.start_soon(
|
505
|
-
partial(
|
506
|
-
critical_service_loop,
|
507
|
-
workload=runner._check_for_cancelled_flow_runs,
|
508
|
-
interval=self.query_seconds * 2,
|
509
|
-
run_once=run_once,
|
510
|
-
jitter_range=0.3,
|
511
|
-
)
|
512
|
-
)
|
513
501
|
|
514
502
|
def execute_in_background(
|
515
503
|
self, func: Callable[..., Any], *args: Any, **kwargs: Any
|
@@ -583,58 +571,42 @@ class Runner:
|
|
583
571
|
if not self._acquire_limit_slot(flow_run_id):
|
584
572
|
return
|
585
573
|
|
586
|
-
|
587
|
-
|
588
|
-
self._submitting_flow_run_ids.add(flow_run_id)
|
589
|
-
flow_run = await self._client.read_flow_run(flow_run_id)
|
590
|
-
|
591
|
-
process: (
|
592
|
-
anyio.abc.Process | Exception
|
593
|
-
) = await self._runs_task_group.start(
|
594
|
-
partial(
|
595
|
-
self._submit_run_and_capture_errors,
|
596
|
-
flow_run=flow_run,
|
597
|
-
entrypoint=entrypoint,
|
598
|
-
command=command,
|
599
|
-
cwd=cwd,
|
600
|
-
env=env,
|
601
|
-
stream_output=stream_output,
|
602
|
-
),
|
603
|
-
)
|
604
|
-
if isinstance(process, Exception):
|
605
|
-
return
|
574
|
+
self._submitting_flow_run_ids.add(flow_run_id)
|
575
|
+
flow_run = await self._client.read_flow_run(flow_run_id)
|
606
576
|
|
607
|
-
|
577
|
+
process: anyio.abc.Process | Exception = await self._runs_task_group.start(
|
578
|
+
partial(
|
579
|
+
self._submit_run_and_capture_errors,
|
580
|
+
flow_run=flow_run,
|
581
|
+
entrypoint=entrypoint,
|
582
|
+
command=command,
|
583
|
+
cwd=cwd,
|
584
|
+
env=env,
|
585
|
+
stream_output=stream_output,
|
586
|
+
),
|
587
|
+
)
|
588
|
+
if isinstance(process, Exception):
|
589
|
+
return
|
608
590
|
|
609
|
-
|
610
|
-
await self._emit_flow_run_heartbeat(flow_run)
|
591
|
+
task_status.started(process.pid)
|
611
592
|
|
612
|
-
|
613
|
-
|
614
|
-
if process.returncode is None:
|
615
|
-
self._flow_run_process_map[flow_run.id] = ProcessMapEntry(
|
616
|
-
pid=process.pid, flow_run=flow_run
|
617
|
-
)
|
593
|
+
if self.heartbeat_seconds is not None:
|
594
|
+
await self._emit_flow_run_heartbeat(flow_run)
|
618
595
|
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
should_stop=lambda: not self._flow_run_process_map,
|
625
|
-
on_stop=tg.cancel_scope.cancel,
|
596
|
+
async with self._flow_run_process_map_lock:
|
597
|
+
# Only add the process to the map if it is still running
|
598
|
+
if process.returncode is None:
|
599
|
+
self._flow_run_process_map[flow_run.id] = ProcessMapEntry(
|
600
|
+
pid=process.pid, flow_run=flow_run
|
626
601
|
)
|
627
602
|
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
jitter_range=0.3,
|
634
|
-
)
|
635
|
-
)
|
603
|
+
while True:
|
604
|
+
# Wait until flow run execution is complete and the process has been removed from the map
|
605
|
+
await anyio.sleep(0.1)
|
606
|
+
if self._flow_run_process_map.get(flow_run.id) is None:
|
607
|
+
break
|
636
608
|
|
637
|
-
|
609
|
+
return process
|
638
610
|
|
639
611
|
async def execute_bundle(
|
640
612
|
self,
|
@@ -673,24 +645,8 @@ class Runner:
|
|
673
645
|
)
|
674
646
|
self._flow_run_bundle_map[flow_run.id] = bundle
|
675
647
|
|
676
|
-
tasks: list[asyncio.Task[None]] = []
|
677
|
-
tasks.append(
|
678
|
-
asyncio.create_task(
|
679
|
-
critical_service_loop(
|
680
|
-
workload=self._check_for_cancelled_flow_runs,
|
681
|
-
interval=self.query_seconds,
|
682
|
-
jitter_range=0.3,
|
683
|
-
)
|
684
|
-
)
|
685
|
-
)
|
686
|
-
|
687
648
|
await anyio.to_thread.run_sync(process.join)
|
688
649
|
|
689
|
-
for task in tasks:
|
690
|
-
task.cancel()
|
691
|
-
|
692
|
-
await asyncio.gather(*tasks, return_exceptions=True)
|
693
|
-
|
694
650
|
self._flow_run_process_map.pop(flow_run.id)
|
695
651
|
|
696
652
|
flow_run_logger = self._get_flow_run_logger(flow_run)
|
@@ -1000,83 +956,11 @@ class Runner:
|
|
1000
956
|
self.last_polled: datetime.datetime = now("UTC")
|
1001
957
|
return await self._submit_scheduled_flow_runs(flow_run_response=runs_response)
|
1002
958
|
|
1003
|
-
async def
|
1004
|
-
self,
|
1005
|
-
should_stop: Callable[[], bool] = lambda: False,
|
1006
|
-
on_stop: Callable[[], None] = lambda: None,
|
959
|
+
async def _cancel_run(
|
960
|
+
self, flow_run: "FlowRun | uuid.UUID", state_msg: Optional[str] = None
|
1007
961
|
):
|
1008
|
-
|
1009
|
-
|
1010
|
-
cancel them.
|
1011
|
-
|
1012
|
-
Args:
|
1013
|
-
should_stop: A callable that returns a boolean indicating whether or not
|
1014
|
-
the runner should stop checking for cancelled flow runs.
|
1015
|
-
on_stop: A callable that is called when the runner should stop checking
|
1016
|
-
for cancelled flow runs.
|
1017
|
-
"""
|
1018
|
-
if self.stopping:
|
1019
|
-
return
|
1020
|
-
if not self.started:
|
1021
|
-
raise RuntimeError(
|
1022
|
-
"Runner is not set up. Please make sure you are running this runner "
|
1023
|
-
"as an async context manager."
|
1024
|
-
)
|
1025
|
-
|
1026
|
-
if should_stop():
|
1027
|
-
self._logger.debug(
|
1028
|
-
"Runner has no active flow runs or deployments. Sending message to loop"
|
1029
|
-
" service that no further cancellation checks are needed."
|
1030
|
-
)
|
1031
|
-
on_stop()
|
1032
|
-
|
1033
|
-
self._logger.debug("Checking for cancelled flow runs...")
|
1034
|
-
|
1035
|
-
named_cancelling_flow_runs = await self._client.read_flow_runs(
|
1036
|
-
flow_run_filter=FlowRunFilter(
|
1037
|
-
state=FlowRunFilterState(
|
1038
|
-
type=FlowRunFilterStateType(any_=[StateType.CANCELLED]),
|
1039
|
-
name=FlowRunFilterStateName(any_=["Cancelling"]),
|
1040
|
-
),
|
1041
|
-
# Avoid duplicate cancellation calls
|
1042
|
-
id=FlowRunFilterId(
|
1043
|
-
any_=list(
|
1044
|
-
self._flow_run_process_map.keys()
|
1045
|
-
- self._cancelling_flow_run_ids
|
1046
|
-
)
|
1047
|
-
),
|
1048
|
-
),
|
1049
|
-
)
|
1050
|
-
|
1051
|
-
typed_cancelling_flow_runs = await self._client.read_flow_runs(
|
1052
|
-
flow_run_filter=FlowRunFilter(
|
1053
|
-
state=FlowRunFilterState(
|
1054
|
-
type=FlowRunFilterStateType(any_=[StateType.CANCELLING]),
|
1055
|
-
),
|
1056
|
-
# Avoid duplicate cancellation calls
|
1057
|
-
id=FlowRunFilterId(
|
1058
|
-
any_=list(
|
1059
|
-
self._flow_run_process_map.keys()
|
1060
|
-
- self._cancelling_flow_run_ids
|
1061
|
-
)
|
1062
|
-
),
|
1063
|
-
),
|
1064
|
-
)
|
1065
|
-
|
1066
|
-
cancelling_flow_runs = named_cancelling_flow_runs + typed_cancelling_flow_runs
|
1067
|
-
|
1068
|
-
if cancelling_flow_runs:
|
1069
|
-
self._logger.info(
|
1070
|
-
f"Found {len(cancelling_flow_runs)} flow runs awaiting cancellation."
|
1071
|
-
)
|
1072
|
-
|
1073
|
-
for flow_run in cancelling_flow_runs:
|
1074
|
-
self._cancelling_flow_run_ids.add(flow_run.id)
|
1075
|
-
self._runs_task_group.start_soon(self._cancel_run, flow_run)
|
1076
|
-
|
1077
|
-
return cancelling_flow_runs
|
1078
|
-
|
1079
|
-
async def _cancel_run(self, flow_run: "FlowRun", state_msg: Optional[str] = None):
|
962
|
+
if isinstance(flow_run, uuid.UUID):
|
963
|
+
flow_run = await self._client.read_flow_run(flow_run)
|
1080
964
|
run_logger = self._get_flow_run_logger(flow_run)
|
1081
965
|
|
1082
966
|
process_map_entry = self._flow_run_process_map.get(flow_run.id)
|
@@ -1543,43 +1427,6 @@ class Runner:
|
|
1543
1427
|
|
1544
1428
|
await self._client.set_flow_run_state(flow_run.id, state, force=True)
|
1545
1429
|
|
1546
|
-
# Do not remove the flow run from the cancelling set immediately because
|
1547
|
-
# the API caches responses for the `read_flow_runs` and we do not want to
|
1548
|
-
# duplicate cancellations.
|
1549
|
-
await self._schedule_task(
|
1550
|
-
60 * 10, self._cancelling_flow_run_ids.remove, flow_run.id
|
1551
|
-
)
|
1552
|
-
|
1553
|
-
async def _schedule_task(
|
1554
|
-
self, __in_seconds: int, fn: Callable[..., Any], *args: Any, **kwargs: Any
|
1555
|
-
) -> None:
|
1556
|
-
"""
|
1557
|
-
Schedule a background task to start after some time.
|
1558
|
-
|
1559
|
-
These tasks will be run immediately when the runner exits instead of waiting.
|
1560
|
-
|
1561
|
-
The function may be async or sync. Async functions will be awaited.
|
1562
|
-
"""
|
1563
|
-
|
1564
|
-
async def wrapper(task_status: anyio.abc.TaskStatus[None]) -> None:
|
1565
|
-
# If we are shutting down, do not sleep; otherwise sleep until the scheduled
|
1566
|
-
# time or shutdown
|
1567
|
-
if self.started:
|
1568
|
-
with anyio.CancelScope() as scope:
|
1569
|
-
self._scheduled_task_scopes.add(scope)
|
1570
|
-
task_status.started()
|
1571
|
-
await anyio.sleep(__in_seconds)
|
1572
|
-
|
1573
|
-
self._scheduled_task_scopes.remove(scope)
|
1574
|
-
else:
|
1575
|
-
task_status.started()
|
1576
|
-
|
1577
|
-
result = fn(*args, **kwargs)
|
1578
|
-
if asyncio.iscoroutine(result):
|
1579
|
-
await result
|
1580
|
-
|
1581
|
-
await self._runs_task_group.start(wrapper)
|
1582
|
-
|
1583
1430
|
async def _run_on_cancellation_hooks(
|
1584
1431
|
self,
|
1585
1432
|
flow_run: "FlowRun",
|
@@ -1647,11 +1494,18 @@ class Runner:
|
|
1647
1494
|
if not hasattr(self, "_loop") or not self._loop:
|
1648
1495
|
self._loop = asyncio.get_event_loop()
|
1649
1496
|
|
1650
|
-
await self.
|
1497
|
+
await self._exit_stack.enter_async_context(
|
1498
|
+
FlowRunCancellingObserver(
|
1499
|
+
on_cancelling=lambda flow_run_id: self._runs_task_group.start_soon(
|
1500
|
+
self._cancel_run, flow_run_id
|
1501
|
+
)
|
1502
|
+
)
|
1503
|
+
)
|
1504
|
+
await self._exit_stack.enter_async_context(self._client)
|
1651
1505
|
|
1652
1506
|
if not hasattr(self, "_runs_task_group") or not self._runs_task_group:
|
1653
1507
|
self._runs_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
|
1654
|
-
await self.
|
1508
|
+
await self._exit_stack.enter_async_context(self._runs_task_group)
|
1655
1509
|
|
1656
1510
|
if not hasattr(self, "_loops_task_group") or not self._loops_task_group:
|
1657
1511
|
self._loops_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
|
@@ -1677,11 +1531,7 @@ class Runner:
|
|
1677
1531
|
for scope in self._scheduled_task_scopes:
|
1678
1532
|
scope.cancel()
|
1679
1533
|
|
1680
|
-
|
1681
|
-
await self._runs_task_group.__aexit__(*exc_info)
|
1682
|
-
|
1683
|
-
if self._client:
|
1684
|
-
await self._client.__aexit__(*exc_info)
|
1534
|
+
await self._exit_stack.__aexit__(*exc_info)
|
1685
1535
|
|
1686
1536
|
shutil.rmtree(str(self._tmp_dir))
|
1687
1537
|
del self._runs_task_group, self._loops_task_group
|
prefect/tasks.py
CHANGED
@@ -1551,7 +1551,7 @@ class Task(Generic[P, R]):
|
|
1551
1551
|
validated_state=task_run.state,
|
1552
1552
|
)
|
1553
1553
|
|
1554
|
-
if task_run_url := url_for(task_run):
|
1554
|
+
if get_current_settings().ui_url and (task_run_url := url_for(task_run)):
|
1555
1555
|
logger.info(
|
1556
1556
|
f"Created task run {task_run.name!r}. View it in the UI at {task_run_url!r}"
|
1557
1557
|
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
2
2
|
prefect/__init__.py,sha256=iCdcC5ZmeewikCdnPEP6YBAjPNV5dvfxpYCTpw30Hkw,3685
|
3
3
|
prefect/__main__.py,sha256=WFjw3kaYJY6pOTA7WDOgqjsz8zUEUZHCcj3P5wyVa-g,66
|
4
|
-
prefect/_build_info.py,sha256=
|
4
|
+
prefect/_build_info.py,sha256=qHCpV6KpRqnsAiZVjqF9RvA2dX5er6gG6lSsXYjxJw4,185
|
5
5
|
prefect/_result_records.py,sha256=S6QmsODkehGVSzbMm6ig022PYbI6gNKz671p_8kBYx4,7789
|
6
6
|
prefect/_versioning.py,sha256=YqR5cxXrY4P6LM1Pmhd8iMo7v_G2KJpGNdsf4EvDFQ0,14132
|
7
7
|
prefect/_waiters.py,sha256=Ia2ITaXdHzevtyWIgJoOg95lrEXQqNEOquHvw3T33UQ,9026
|
@@ -28,7 +28,7 @@ prefect/task_engine.py,sha256=j0rr8IyBinJmKPD-486RYWKZakhifkEE9ppPCJ9Es-U,62463
|
|
28
28
|
prefect/task_runners.py,sha256=vzJ1kiW1z90Fkkg21QNhPwjfLoDy6rVsUAToXqb6FUE,16206
|
29
29
|
prefect/task_runs.py,sha256=7LIzfo3fondCyEUpU05sYFN5IfpZigBDXrhG5yc-8t0,9039
|
30
30
|
prefect/task_worker.py,sha256=gMj_rl4EjTrnJ5YSOXinC6y-7KSK7fRQt_UYbZbrrV8,17879
|
31
|
-
prefect/tasks.py,sha256=
|
31
|
+
prefect/tasks.py,sha256=DODF_1xPDQVvj_paJDWm43RS46Jdx9_7b2huqT_QyiM,74778
|
32
32
|
prefect/transactions.py,sha256=uIoPNudzJzH6NrMJhrgr5lyh6JxOJQqT1GvrXt69yNw,26068
|
33
33
|
prefect/variables.py,sha256=dCK3vX7TbkqXZhnNT_v7rcGh3ISRqoR6pJVLpoll3Js,8342
|
34
34
|
prefect/_experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -82,9 +82,9 @@ prefect/client/base.py,sha256=7VAMyoy8KtmtI-H8KYsI16_uw9TlrXSrcxChFuMp65Q,26269
|
|
82
82
|
prefect/client/cloud.py,sha256=jnFgg0osMVDGbLjdWkDX3rQg_0pI_zvfSlU480XCWGQ,6523
|
83
83
|
prefect/client/collections.py,sha256=t9XkVU_onQMZ871L21F1oZnAiPSQeeVfd_MuDEBS3iM,1050
|
84
84
|
prefect/client/constants.py,sha256=Z_GG8KF70vbbXxpJuqW5pLnwzujTVeHbcYYRikNmGH0,29
|
85
|
-
prefect/client/subscriptions.py,sha256=
|
85
|
+
prefect/client/subscriptions.py,sha256=PTYi1Pp7rX-aGdcxZkxRBZkZnpzBt1P17APsm05EDR8,4376
|
86
86
|
prefect/client/utilities.py,sha256=UEJD6nwYg2mD8-GSmru-E2ofXaBlmSFZ2-8T_5rIK6c,3472
|
87
|
-
prefect/client/orchestration/__init__.py,sha256=
|
87
|
+
prefect/client/orchestration/__init__.py,sha256=DPbazZvQDgoSZipuNk4z_AILgJbM6zBld-1OsVH55ME,55831
|
88
88
|
prefect/client/orchestration/base.py,sha256=HM6ryHBZSzuHoCFQM9u5qR5k1dN9Bbr_ah6z1UPNbZQ,1542
|
89
89
|
prefect/client/orchestration/routes.py,sha256=_-HC-EmgMhsYdmGwZTxIXlINaVzYuX7RZAvzjHbVp-4,4266
|
90
90
|
prefect/client/orchestration/_artifacts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -148,7 +148,7 @@ prefect/docker/__init__.py,sha256=z6wdc6UFfiBG2jb9Jk64uCWVM04JKVWeVyDWwuuon8M,52
|
|
148
148
|
prefect/docker/docker_image.py,sha256=bR_pEq5-FDxlwTj8CP_7nwZ_MiGK6KxIi8v7DRjy1Kg,3138
|
149
149
|
prefect/events/__init__.py,sha256=GtKl2bE--pJduTxelH2xy7SadlLJmmis8WR1EYixhuA,2094
|
150
150
|
prefect/events/actions.py,sha256=A7jS8bo4zWGnrt3QfSoQs0uYC1xfKXio3IfU0XtTb5s,9129
|
151
|
-
prefect/events/clients.py,sha256=
|
151
|
+
prefect/events/clients.py,sha256=gp3orepQav99303OC-zK6uz3dpyLlLpQ9ZWJEDol0cs,27597
|
152
152
|
prefect/events/filters.py,sha256=2hVfzc3Rdgy0mBHDutWxT__LJY0zpVM8greWX3y6kjM,8233
|
153
153
|
prefect/events/related.py,sha256=CTeexYUmmA93V4gsR33GIFmw-SS-X_ouOpRg-oeq-BU,6672
|
154
154
|
prefect/events/utilities.py,sha256=ww34bTMENCNwcp6RhhgzG0KgXOvKGe0MKmBdSJ8NpZY,3043
|
@@ -184,7 +184,8 @@ prefect/logging/highlighters.py,sha256=BCf_LNhFInIfGPqwuu8YVrGa4wVxNc4YXo2pYgftp
|
|
184
184
|
prefect/logging/loggers.py,sha256=rwFJv0i3dhdKr25XX-xUkQy4Vv4dy18bTy366jrC0OQ,12741
|
185
185
|
prefect/logging/logging.yml,sha256=tT7gTyC4NmngFSqFkCdHaw7R0GPNPDDsTCGZQByiJAQ,3169
|
186
186
|
prefect/runner/__init__.py,sha256=pQBd9wVrUVUDUFJlgiweKSnbahoBZwqnd2O2jkhrULY,158
|
187
|
-
prefect/runner/
|
187
|
+
prefect/runner/_observers.py,sha256=PpyXQL5bjp86AnDFEzcFPS5ayL6ExqcYgyuBMMQCO9Q,2183
|
188
|
+
prefect/runner/runner.py,sha256=DFgZQTkKwmCDMmfA640xY1oTOCURzTOo7HOtwQxRVwA,59443
|
188
189
|
prefect/runner/server.py,sha256=YRYFNoYddA9XfiTIYtudxrnD1vCX-PaOLhvyGUOb9AQ,11966
|
189
190
|
prefect/runner/storage.py,sha256=n-65YoEf7KNVInnmMPeP5TVFJOa2zOS8w9en9MHi6uo,31328
|
190
191
|
prefect/runner/submit.py,sha256=qOEj-NChQ6RYFV35hHEVMTklrNmKwaGs2mR78ku9H0o,9474
|
@@ -318,7 +319,7 @@ prefect/workers/cloud.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
|
318
319
|
prefect/workers/process.py,sha256=Yi5D0U5AQ51wHT86GdwtImXSefe0gJf3LGq4r4z9zwM,11090
|
319
320
|
prefect/workers/server.py,sha256=2pmVeJZiVbEK02SO6BEZaBIvHMsn6G8LzjW8BXyiTtk,1952
|
320
321
|
prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
|
321
|
-
prefect_client-3.4.
|
322
|
-
prefect_client-3.4.
|
323
|
-
prefect_client-3.4.
|
324
|
-
prefect_client-3.4.
|
322
|
+
prefect_client-3.4.1.dev2.dist-info/METADATA,sha256=SrQm0IQPihKCyz3wiIcpgc7slcilDL4wdt9-gV9G2xk,7471
|
323
|
+
prefect_client-3.4.1.dev2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
324
|
+
prefect_client-3.4.1.dev2.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
325
|
+
prefect_client-3.4.1.dev2.dist-info/RECORD,,
|
File without changes
|
File without changes
|