prefect-client 3.1.7__py3-none-any.whl → 3.1.8__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/_version.py +3 -3
- prefect/client/orchestration.py +18 -0
- prefect/runner/runner.py +129 -18
- prefect/settings/__init__.py +1 -0
- prefect/settings/base.py +3 -2
- prefect/settings/models/api.py +4 -0
- prefect/settings/models/runner.py +8 -0
- prefect/settings/models/server/api.py +7 -1
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.8.dist-info}/METADATA +1 -1
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.8.dist-info}/RECORD +13 -13
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.8.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.8.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.7.dist-info → prefect_client-3.1.8.dist-info}/top_level.txt +0 -0
prefect/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2024-12-
|
11
|
+
"date": "2024-12-17T10:20:43-0800",
|
12
12
|
"dirty": true,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "3.1.
|
14
|
+
"full-revisionid": "53a83ebc4a9a26a1d7cfd91d6be7cf6bd30e7f21",
|
15
|
+
"version": "3.1.8"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
prefect/client/orchestration.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import base64
|
2
3
|
import datetime
|
3
4
|
import ssl
|
4
5
|
import warnings
|
@@ -114,6 +115,7 @@ from prefect.events import filters
|
|
114
115
|
from prefect.events.schemas.automations import Automation, AutomationCore
|
115
116
|
from prefect.logging import get_logger
|
116
117
|
from prefect.settings import (
|
118
|
+
PREFECT_API_AUTH_STRING,
|
117
119
|
PREFECT_API_DATABASE_CONNECTION_URL,
|
118
120
|
PREFECT_API_ENABLE_HTTP2,
|
119
121
|
PREFECT_API_KEY,
|
@@ -228,6 +230,7 @@ def get_client(
|
|
228
230
|
if sync_client:
|
229
231
|
return SyncPrefectClient(
|
230
232
|
api,
|
233
|
+
auth_string=PREFECT_API_AUTH_STRING.value(),
|
231
234
|
api_key=PREFECT_API_KEY.value(),
|
232
235
|
httpx_settings=httpx_settings,
|
233
236
|
server_type=server_type,
|
@@ -235,6 +238,7 @@ def get_client(
|
|
235
238
|
else:
|
236
239
|
return PrefectClient(
|
237
240
|
api,
|
241
|
+
auth_string=PREFECT_API_AUTH_STRING.value(),
|
238
242
|
api_key=PREFECT_API_KEY.value(),
|
239
243
|
httpx_settings=httpx_settings,
|
240
244
|
server_type=server_type,
|
@@ -271,6 +275,7 @@ class PrefectClient:
|
|
271
275
|
self,
|
272
276
|
api: Union[str, ASGIApp],
|
273
277
|
*,
|
278
|
+
auth_string: Optional[str] = None,
|
274
279
|
api_key: Optional[str] = None,
|
275
280
|
api_version: Optional[str] = None,
|
276
281
|
httpx_settings: Optional[dict[str, Any]] = None,
|
@@ -299,6 +304,10 @@ class PrefectClient:
|
|
299
304
|
if api_key:
|
300
305
|
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
301
306
|
|
307
|
+
if auth_string:
|
308
|
+
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
309
|
+
httpx_settings["headers"].setdefault("Authorization", f"Basic {token}")
|
310
|
+
|
302
311
|
# Context management
|
303
312
|
self._context_stack: int = 0
|
304
313
|
self._exit_stack = AsyncExitStack()
|
@@ -3469,6 +3478,8 @@ class PrefectClient:
|
|
3469
3478
|
try:
|
3470
3479
|
api_version = await self.api_version()
|
3471
3480
|
except Exception as e:
|
3481
|
+
if "Unauthorized" in str(e):
|
3482
|
+
raise e
|
3472
3483
|
raise RuntimeError(f"Failed to reach API at {self.api_url}") from e
|
3473
3484
|
|
3474
3485
|
api_version = version.parse(api_version)
|
@@ -3590,6 +3601,7 @@ class SyncPrefectClient:
|
|
3590
3601
|
self,
|
3591
3602
|
api: Union[str, ASGIApp],
|
3592
3603
|
*,
|
3604
|
+
auth_string: Optional[str] = None,
|
3593
3605
|
api_key: Optional[str] = None,
|
3594
3606
|
api_version: Optional[str] = None,
|
3595
3607
|
httpx_settings: Optional[dict[str, Any]] = None,
|
@@ -3618,6 +3630,10 @@ class SyncPrefectClient:
|
|
3618
3630
|
if api_key:
|
3619
3631
|
httpx_settings["headers"].setdefault("Authorization", f"Bearer {api_key}")
|
3620
3632
|
|
3633
|
+
if auth_string:
|
3634
|
+
token = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8")
|
3635
|
+
httpx_settings["headers"].setdefault("Authorization", f"Basic {token}")
|
3636
|
+
|
3621
3637
|
# Context management
|
3622
3638
|
self._context_stack: int = 0
|
3623
3639
|
self._ephemeral_app: Optional[ASGIApp] = None
|
@@ -3800,6 +3816,8 @@ class SyncPrefectClient:
|
|
3800
3816
|
try:
|
3801
3817
|
api_version = self.api_version()
|
3802
3818
|
except Exception as e:
|
3819
|
+
if "Unauthorized" in str(e):
|
3820
|
+
raise e
|
3803
3821
|
raise RuntimeError(f"Failed to reach API at {self.api_url}") from e
|
3804
3822
|
|
3805
3823
|
api_version = version.parse(api_version)
|
prefect/runner/runner.py
CHANGED
@@ -47,11 +47,12 @@ from typing import (
|
|
47
47
|
TYPE_CHECKING,
|
48
48
|
Any,
|
49
49
|
Callable,
|
50
|
+
Coroutine,
|
50
51
|
Dict,
|
51
52
|
Iterable,
|
52
53
|
List,
|
53
54
|
Optional,
|
54
|
-
|
55
|
+
TypedDict,
|
55
56
|
Union,
|
56
57
|
)
|
57
58
|
from uuid import UUID, uuid4
|
@@ -59,6 +60,7 @@ from uuid import UUID, uuid4
|
|
59
60
|
import anyio
|
60
61
|
import anyio.abc
|
61
62
|
import pendulum
|
63
|
+
from cachetools import LRUCache
|
62
64
|
|
63
65
|
from prefect._internal.concurrency.api import (
|
64
66
|
create_call,
|
@@ -94,8 +96,6 @@ from prefect.logging.loggers import PrefectLogAdapter, flow_run_logger, get_logg
|
|
94
96
|
from prefect.runner.storage import RunnerStorage
|
95
97
|
from prefect.settings import (
|
96
98
|
PREFECT_API_URL,
|
97
|
-
PREFECT_RUNNER_POLL_FREQUENCY,
|
98
|
-
PREFECT_RUNNER_PROCESS_LIMIT,
|
99
99
|
PREFECT_RUNNER_SERVER_ENABLE,
|
100
100
|
get_current_settings,
|
101
101
|
)
|
@@ -123,19 +123,25 @@ from prefect.utilities.services import (
|
|
123
123
|
from prefect.utilities.slugify import slugify
|
124
124
|
|
125
125
|
if TYPE_CHECKING:
|
126
|
-
from prefect.client.schemas.
|
126
|
+
from prefect.client.schemas.responses import DeploymentResponse
|
127
127
|
from prefect.client.types.flexible_schedule_list import FlexibleScheduleList
|
128
128
|
from prefect.deployments.runner import RunnerDeployment
|
129
129
|
|
130
130
|
__all__ = ["Runner"]
|
131
131
|
|
132
132
|
|
133
|
+
class ProcessMapEntry(TypedDict):
|
134
|
+
flow_run: FlowRun
|
135
|
+
pid: int
|
136
|
+
|
137
|
+
|
133
138
|
class Runner:
|
134
139
|
def __init__(
|
135
140
|
self,
|
136
141
|
name: Optional[str] = None,
|
137
142
|
query_seconds: Optional[float] = None,
|
138
143
|
prefetch_seconds: float = 10,
|
144
|
+
heartbeat_seconds: Optional[float] = None,
|
139
145
|
limit: Optional[int] = None,
|
140
146
|
pause_on_shutdown: bool = True,
|
141
147
|
webserver: bool = False,
|
@@ -149,6 +155,9 @@ class Runner:
|
|
149
155
|
query_seconds: The number of seconds to wait between querying for
|
150
156
|
scheduled flow runs; defaults to `PREFECT_RUNNER_POLL_FREQUENCY`
|
151
157
|
prefetch_seconds: The number of seconds to prefetch flow runs for.
|
158
|
+
heartbeat_seconds: The number of seconds to wait between emitting
|
159
|
+
flow run heartbeats. The runner will not emit heartbeats if the value is None.
|
160
|
+
Defaults to `PREFECT_RUNNER_HEARTBEAT_FREQUENCY`.
|
152
161
|
limit: The maximum number of flow runs this runner should be running at
|
153
162
|
pause_on_shutdown: A boolean for whether or not to automatically pause
|
154
163
|
deployment schedules on shutdown; defaults to `True`
|
@@ -180,6 +189,8 @@ class Runner:
|
|
180
189
|
asyncio.run(runner.start())
|
181
190
|
```
|
182
191
|
"""
|
192
|
+
settings = get_current_settings()
|
193
|
+
|
183
194
|
if name and ("/" in name or "%" in name):
|
184
195
|
raise ValueError("Runner name cannot contain '/' or '%'")
|
185
196
|
self.name = Path(name).stem if name is not None else f"runner-{uuid4()}"
|
@@ -188,19 +199,24 @@ class Runner:
|
|
188
199
|
self.started = False
|
189
200
|
self.stopping = False
|
190
201
|
self.pause_on_shutdown = pause_on_shutdown
|
191
|
-
self.limit = limit or
|
202
|
+
self.limit = limit or settings.runner.process_limit
|
192
203
|
self.webserver = webserver
|
193
204
|
|
194
|
-
self.query_seconds = query_seconds or
|
205
|
+
self.query_seconds = query_seconds or settings.runner.poll_frequency
|
195
206
|
self._prefetch_seconds = prefetch_seconds
|
207
|
+
self.heartbeat_seconds = (
|
208
|
+
heartbeat_seconds or settings.runner.heartbeat_frequency
|
209
|
+
)
|
210
|
+
if self.heartbeat_seconds is not None and self.heartbeat_seconds < 30:
|
211
|
+
raise ValueError("Heartbeat must be 30 seconds or greater.")
|
196
212
|
|
197
213
|
self._limiter: Optional[anyio.CapacityLimiter] = None
|
198
214
|
self._client = get_client()
|
199
|
-
self._submitting_flow_run_ids = set()
|
200
|
-
self._cancelling_flow_run_ids = set()
|
201
|
-
self._scheduled_task_scopes = set()
|
202
|
-
self._deployment_ids:
|
203
|
-
self._flow_run_process_map: dict[UUID,
|
215
|
+
self._submitting_flow_run_ids: set[UUID] = set()
|
216
|
+
self._cancelling_flow_run_ids: set[UUID] = set()
|
217
|
+
self._scheduled_task_scopes: set[UUID] = set()
|
218
|
+
self._deployment_ids: set[UUID] = set()
|
219
|
+
self._flow_run_process_map: dict[UUID, ProcessMapEntry] = dict()
|
204
220
|
|
205
221
|
self._tmp_dir: Path = (
|
206
222
|
Path(tempfile.gettempdir()) / "runner_storage" / str(uuid4())
|
@@ -210,6 +226,12 @@ class Runner:
|
|
210
226
|
|
211
227
|
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
212
228
|
|
229
|
+
# Caching
|
230
|
+
self._deployment_cache: LRUCache[UUID, "DeploymentResponse"] = LRUCache(
|
231
|
+
maxsize=100
|
232
|
+
)
|
233
|
+
self._flow_cache: LRUCache[UUID, "APIFlow"] = LRUCache(maxsize=100)
|
234
|
+
|
213
235
|
@sync_compatible
|
214
236
|
async def add_deployment(
|
215
237
|
self,
|
@@ -234,7 +256,7 @@ class Runner:
|
|
234
256
|
@sync_compatible
|
235
257
|
async def add_flow(
|
236
258
|
self,
|
237
|
-
flow: Flow,
|
259
|
+
flow: Flow[Any, Any],
|
238
260
|
name: Optional[str] = None,
|
239
261
|
interval: Optional[
|
240
262
|
Union[
|
@@ -249,7 +271,7 @@ class Runner:
|
|
249
271
|
paused: Optional[bool] = None,
|
250
272
|
schedules: Optional["FlexibleScheduleList"] = None,
|
251
273
|
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
252
|
-
parameters: Optional[dict] = None,
|
274
|
+
parameters: Optional[dict[str, Any]] = None,
|
253
275
|
triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
254
276
|
description: Optional[str] = None,
|
255
277
|
tags: Optional[List[str]] = None,
|
@@ -336,7 +358,7 @@ class Runner:
|
|
336
358
|
else:
|
337
359
|
return next(s for s in self._storage_objs if s == storage)
|
338
360
|
|
339
|
-
def handle_sigterm(self,
|
361
|
+
def handle_sigterm(self, **kwargs: Any) -> None:
|
340
362
|
"""
|
341
363
|
Gracefully shuts down the runner when a SIGTERM is received.
|
342
364
|
"""
|
@@ -441,6 +463,16 @@ class Runner:
|
|
441
463
|
jitter_range=0.3,
|
442
464
|
)
|
443
465
|
)
|
466
|
+
if self.heartbeat_seconds is not None:
|
467
|
+
loops_task_group.start_soon(
|
468
|
+
partial(
|
469
|
+
critical_service_loop,
|
470
|
+
workload=runner._emit_flow_run_heartbeats,
|
471
|
+
interval=self.heartbeat_seconds,
|
472
|
+
run_once=run_once,
|
473
|
+
jitter_range=0.3,
|
474
|
+
)
|
475
|
+
)
|
444
476
|
|
445
477
|
def execute_in_background(
|
446
478
|
self, func: Callable[..., Any], *args: Any, **kwargs: Any
|
@@ -538,6 +570,15 @@ class Runner:
|
|
538
570
|
jitter_range=0.3,
|
539
571
|
)
|
540
572
|
)
|
573
|
+
if self.heartbeat_seconds is not None:
|
574
|
+
tg.start_soon(
|
575
|
+
partial(
|
576
|
+
critical_service_loop,
|
577
|
+
workload=self._emit_flow_run_heartbeats,
|
578
|
+
interval=self.heartbeat_seconds,
|
579
|
+
jitter_range=0.3,
|
580
|
+
)
|
581
|
+
)
|
541
582
|
|
542
583
|
def _get_flow_run_logger(self, flow_run: "FlowRun") -> PrefectLogAdapter:
|
543
584
|
return flow_run_logger(flow_run=flow_run).getChild(
|
@@ -850,18 +891,84 @@ class Runner:
|
|
850
891
|
"message": state_msg or "Flow run was cancelled successfully."
|
851
892
|
},
|
852
893
|
)
|
894
|
+
|
895
|
+
flow, deployment = await self._get_flow_and_deployment(flow_run)
|
896
|
+
self._emit_flow_run_cancelled_event(
|
897
|
+
flow_run=flow_run, flow=flow, deployment=deployment
|
898
|
+
)
|
899
|
+
run_logger.info(f"Cancelled flow run '{flow_run.name}'!")
|
900
|
+
|
901
|
+
async def _get_flow_and_deployment(
|
902
|
+
self, flow_run: "FlowRun"
|
903
|
+
) -> tuple[Optional["APIFlow"], Optional["DeploymentResponse"]]:
|
904
|
+
deployment: Optional["DeploymentResponse"] = (
|
905
|
+
self._deployment_cache.get(flow_run.deployment_id)
|
906
|
+
if flow_run.deployment_id
|
907
|
+
else None
|
908
|
+
)
|
909
|
+
flow: Optional["APIFlow"] = self._flow_cache.get(flow_run.flow_id)
|
910
|
+
if not deployment and flow_run.deployment_id is not None:
|
853
911
|
try:
|
854
912
|
deployment = await self._client.read_deployment(flow_run.deployment_id)
|
913
|
+
self._deployment_cache[flow_run.deployment_id] = deployment
|
855
914
|
except ObjectNotFound:
|
856
915
|
deployment = None
|
916
|
+
if not flow:
|
857
917
|
try:
|
858
918
|
flow = await self._client.read_flow(flow_run.flow_id)
|
919
|
+
self._flow_cache[flow_run.flow_id] = flow
|
859
920
|
except ObjectNotFound:
|
860
921
|
flow = None
|
861
|
-
|
862
|
-
|
922
|
+
return flow, deployment
|
923
|
+
|
924
|
+
async def _emit_flow_run_heartbeats(self):
|
925
|
+
coros: list[Coroutine[Any, Any, Any]] = []
|
926
|
+
for entry in self._flow_run_process_map.values():
|
927
|
+
coros.append(self._emit_flow_run_heartbeat(entry["flow_run"]))
|
928
|
+
await asyncio.gather(*coros)
|
929
|
+
|
930
|
+
async def _emit_flow_run_heartbeat(self, flow_run: "FlowRun"):
|
931
|
+
from prefect import __version__
|
932
|
+
|
933
|
+
related: list[RelatedResource] = []
|
934
|
+
tags: list[str] = []
|
935
|
+
|
936
|
+
flow, deployment = await self._get_flow_and_deployment(flow_run)
|
937
|
+
if deployment:
|
938
|
+
related.append(
|
939
|
+
RelatedResource(
|
940
|
+
{
|
941
|
+
"prefect.resource.id": f"prefect.deployment.{deployment.id}",
|
942
|
+
"prefect.resource.role": "deployment",
|
943
|
+
"prefect.resource.name": deployment.name,
|
944
|
+
}
|
945
|
+
)
|
863
946
|
)
|
864
|
-
|
947
|
+
tags.extend(deployment.tags)
|
948
|
+
if flow:
|
949
|
+
related.append(
|
950
|
+
RelatedResource(
|
951
|
+
{
|
952
|
+
"prefect.resource.id": f"prefect.flow.{flow.id}",
|
953
|
+
"prefect.resource.role": "flow",
|
954
|
+
"prefect.resource.name": flow.name,
|
955
|
+
}
|
956
|
+
)
|
957
|
+
)
|
958
|
+
tags.extend(flow_run.tags)
|
959
|
+
|
960
|
+
related = [RelatedResource.model_validate(r) for r in related]
|
961
|
+
related += tags_as_related_resources(set(tags))
|
962
|
+
|
963
|
+
emit_event(
|
964
|
+
event="prefect.flow-run.heartbeat",
|
965
|
+
resource={
|
966
|
+
"prefect.resource.id": f"prefect.flow-run.{flow_run.id}",
|
967
|
+
"prefect.resource.name": flow_run.name,
|
968
|
+
"prefect.version": __version__,
|
969
|
+
},
|
970
|
+
related=related,
|
971
|
+
)
|
865
972
|
|
866
973
|
def _event_resource(self):
|
867
974
|
from prefect import __version__
|
@@ -876,7 +983,7 @@ class Runner:
|
|
876
983
|
self,
|
877
984
|
flow_run: "FlowRun",
|
878
985
|
flow: "Optional[APIFlow]",
|
879
|
-
deployment: "Optional[
|
986
|
+
deployment: "Optional[DeploymentResponse]",
|
880
987
|
):
|
881
988
|
related: list[RelatedResource] = []
|
882
989
|
tags: list[str] = []
|
@@ -920,6 +1027,7 @@ class Runner:
|
|
920
1027
|
resource=self._event_resource(),
|
921
1028
|
related=related,
|
922
1029
|
)
|
1030
|
+
self._logger.debug(f"Emitted flow run heartbeat event for {flow_run.id}")
|
923
1031
|
|
924
1032
|
async def _get_scheduled_flow_runs(
|
925
1033
|
self,
|
@@ -1052,6 +1160,9 @@ class Runner:
|
|
1052
1160
|
self._flow_run_process_map[flow_run.id] = dict(
|
1053
1161
|
pid=readiness_result, flow_run=flow_run
|
1054
1162
|
)
|
1163
|
+
# Heartbeats are opt-in and only emitted if a heartbeat frequency is set
|
1164
|
+
if self.heartbeat_seconds is not None:
|
1165
|
+
await self._emit_flow_run_heartbeat(flow_run)
|
1055
1166
|
|
1056
1167
|
run_logger.info(f"Completed submission of flow run '{flow_run.id}'")
|
1057
1168
|
else:
|
prefect/settings/__init__.py
CHANGED
@@ -53,6 +53,7 @@ __all__ = [ # noqa: F822
|
|
53
53
|
"temporary_settings",
|
54
54
|
"DEFAULT_PROFILES_PATH",
|
55
55
|
# add public settings here for auto-completion
|
56
|
+
"PREFECT_API_AUTH_STRING", # type: ignore
|
56
57
|
"PREFECT_API_KEY", # type: ignore
|
57
58
|
"PREFECT_API_URL", # type: ignore
|
58
59
|
"PREFECT_UI_URL", # type: ignore
|
prefect/settings/base.py
CHANGED
@@ -192,7 +192,7 @@ def _add_environment_variables(
|
|
192
192
|
|
193
193
|
|
194
194
|
def _build_settings_config(
|
195
|
-
path: Tuple[str, ...] = tuple(),
|
195
|
+
path: Tuple[str, ...] = tuple(), frozen: bool = False
|
196
196
|
) -> PrefectSettingsConfigDict:
|
197
197
|
env_prefix = f"PREFECT_{'_'.join(path).upper()}_" if path else "PREFECT_"
|
198
198
|
return PrefectSettingsConfigDict(
|
@@ -202,7 +202,8 @@ def _build_settings_config(
|
|
202
202
|
toml_file="prefect.toml",
|
203
203
|
prefect_toml_table_header=path,
|
204
204
|
pyproject_toml_table_header=("tool", "prefect", *path),
|
205
|
-
json_schema_extra=_add_environment_variables,
|
205
|
+
json_schema_extra=_add_environment_variables, # type: ignore
|
206
|
+
frozen=frozen,
|
206
207
|
)
|
207
208
|
|
208
209
|
|
prefect/settings/models/api.py
CHANGED
@@ -19,6 +19,10 @@ class APISettings(PrefectBaseSettings):
|
|
19
19
|
default=None,
|
20
20
|
description="The URL of the Prefect API. If not set, the client will attempt to infer it.",
|
21
21
|
)
|
22
|
+
auth_string: Optional[SecretStr] = Field(
|
23
|
+
default=None,
|
24
|
+
description="The auth string used for basic authentication with a self-hosted Prefect API. Should be kept secret.",
|
25
|
+
)
|
22
26
|
key: Optional[SecretStr] = Field(
|
23
27
|
default=None,
|
24
28
|
description="The API key used for authentication with the Prefect API. Should be kept secret.",
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
1
3
|
from pydantic import Field
|
2
4
|
|
3
5
|
from prefect.settings.base import PrefectBaseSettings, _build_settings_config
|
@@ -54,6 +56,12 @@ class RunnerSettings(PrefectBaseSettings):
|
|
54
56
|
description="Number of seconds a runner should wait between queries for scheduled work.",
|
55
57
|
)
|
56
58
|
|
59
|
+
heartbeat_frequency: Optional[int] = Field(
|
60
|
+
default=None,
|
61
|
+
description="Number of seconds a runner should wait between heartbeats for flow runs.",
|
62
|
+
ge=30,
|
63
|
+
)
|
64
|
+
|
57
65
|
server: RunnerServerSettings = Field(
|
58
66
|
default_factory=RunnerServerSettings,
|
59
67
|
description="Settings for controlling runner server behavior",
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from datetime import timedelta
|
2
|
+
from typing import Optional
|
2
3
|
|
3
|
-
from pydantic import AliasChoices, AliasPath, Field
|
4
|
+
from pydantic import AliasChoices, AliasPath, Field, SecretStr
|
4
5
|
|
5
6
|
from prefect.settings.base import PrefectBaseSettings, _build_settings_config
|
6
7
|
|
@@ -12,6 +13,11 @@ class ServerAPISettings(PrefectBaseSettings):
|
|
12
13
|
|
13
14
|
model_config = _build_settings_config(("server", "api"))
|
14
15
|
|
16
|
+
auth_string: Optional[SecretStr] = Field(
|
17
|
+
default=None,
|
18
|
+
description="A string to use for basic authentication with the API; typically in the form 'user:password' but can be any string.",
|
19
|
+
)
|
20
|
+
|
15
21
|
host: str = Field(
|
16
22
|
default="127.0.0.1",
|
17
23
|
description="The API's host address (defaults to `127.0.0.1`).",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
2
2
|
prefect/__init__.py,sha256=ueYVH54DQR3_ktv_s3nB0xf_45VEekMsiwVV7aSOgcM,3522
|
3
|
-
prefect/_version.py,sha256=
|
3
|
+
prefect/_version.py,sha256=bscv-D4ssNwrDiU3ekD7QzmIrDtnERxX5XHAG6X-rTE,496
|
4
4
|
prefect/agent.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
|
5
5
|
prefect/artifacts.py,sha256=dsxFWmdg2r9zbHM3KgKOR5YbJ29_dXUYF9kipJpbxkE,13009
|
6
6
|
prefect/automations.py,sha256=T8sUqDriABSuFeuoKUH2OXeCK5YwFfk-mjjM0_Oflyw,5984
|
@@ -72,7 +72,7 @@ prefect/client/base.py,sha256=KJg-RapWjjJp64I-k7s3AlN3rXZQRVz2tYOoAQ6qdTU,25547
|
|
72
72
|
prefect/client/cloud.py,sha256=-Va7ziL5ZnF0a9jz1Pinhmtl5rkw5sTpkBu5eKegSbA,7179
|
73
73
|
prefect/client/collections.py,sha256=OdgJrUssGtuD0tHIYhtBamEN5q4oA6Uv4ZX-QueW7LI,1074
|
74
74
|
prefect/client/constants.py,sha256=Z_GG8KF70vbbXxpJuqW5pLnwzujTVeHbcYYRikNmGH0,29
|
75
|
-
prefect/client/orchestration.py,sha256=
|
75
|
+
prefect/client/orchestration.py,sha256=DQBnvgFZ1jbUMfMKcoP6l5mn6lZlT_0FW2DFcP0ahds,159927
|
76
76
|
prefect/client/subscriptions.py,sha256=TZ7Omv8yeQQIkE6EmWYM78e8p7UdvdTDzcQe91dCU4U,3838
|
77
77
|
prefect/client/utilities.py,sha256=mfU-t5sCm5GV9dLKmUbl2ynixGZJOKXSh3_gjZfA7Vo,3703
|
78
78
|
prefect/client/schemas/__init__.py,sha256=uQqe3HkbW3gBvsIju0ee_ybJ8uuF2z_-DXLjS_O_37w,1063
|
@@ -150,7 +150,7 @@ prefect/records/filesystem.py,sha256=X-h7r5deiHH5IaaDk4ugOCmR5ZKnJeU2cLgp0AkMt0E
|
|
150
150
|
prefect/records/memory.py,sha256=YdzQvEfb-CX0sKxAZK5TaNxVvAlyYlZse9qdoer6Xbk,6447
|
151
151
|
prefect/records/result_store.py,sha256=3ZUFNHCCv_qBQhmIFdvlK_GMnPZcFacaI9dVdDKWdwA,2431
|
152
152
|
prefect/runner/__init__.py,sha256=7U-vAOXFkzMfRz1q8Uv6Otsvc0OrPYLLP44srwkJ_8s,89
|
153
|
-
prefect/runner/runner.py,sha256=
|
153
|
+
prefect/runner/runner.py,sha256=JZbZqv9hy4rp_TAeIQiLfmplfLWe0OLCRVe6vUrh0wE,54005
|
154
154
|
prefect/runner/server.py,sha256=UXlxugqV1SiC49aTnwCDsEdQS6AXyfstaJWukuOBVO8,11171
|
155
155
|
prefect/runner/storage.py,sha256=EkCnutcpcs4X0II81xBtZFGIwqfwRe00W9r6LLfZkQU,24754
|
156
156
|
prefect/runner/submit.py,sha256=DGhBUUIg-N3z788ZqaCcqpIPkvCzQtZeLqjKtQNV1IA,8137
|
@@ -161,8 +161,8 @@ prefect/runtime/flow_run.py,sha256=lX8Y2Y1UALwt-LNuDkCcmQ8zKSMgcW2C26Sn2QMM7V4,1
|
|
161
161
|
prefect/runtime/task_run.py,sha256=B6v_nZiHy9nKZfnKFQF7izZjAjaiZOT0j80m-VcLxmY,3403
|
162
162
|
prefect/server/api/collections_data/views/aggregate-worker-metadata.json,sha256=gqrwGyylzBEzlFSPOJcMuUwdoK_zojpU0SZaBDgK5FE,79748
|
163
163
|
prefect/server/api/static/prefect-logo-mark-gradient.png,sha256=ylRjJkI_JHCw8VbQasNnXQHwZW-sH-IQiUGSD3aWP1E,73430
|
164
|
-
prefect/settings/__init__.py,sha256=
|
165
|
-
prefect/settings/base.py,sha256=
|
164
|
+
prefect/settings/__init__.py,sha256=98gr0K9ovrBz1RQsOIUvYTx2RURbFR5PFKew51Ne314,2070
|
165
|
+
prefect/settings/base.py,sha256=lTekZKFzC8IWr4MiejqroJd4Hx6Hk7xu09wn39S99Ng,8470
|
166
166
|
prefect/settings/constants.py,sha256=5NjVLG1Km9J9I-a6wrq-qmi_dTkPdwEk3IrY9bSxWvw,281
|
167
167
|
prefect/settings/context.py,sha256=yKxnaDJHX8e2jmAVtw1RF9o7X4V3AOcz61sVeQyPX2c,2195
|
168
168
|
prefect/settings/legacy.py,sha256=mkd-kMjQqpsIV5zWjiSNdtZDrK2od-Gk8tzat0rh-JE,5653
|
@@ -170,7 +170,7 @@ prefect/settings/profiles.py,sha256=VZdzOV-KSuAkCxtdhBmSG9i84-K2QLSx6g2-vIUkfig,
|
|
170
170
|
prefect/settings/profiles.toml,sha256=kTvqDNMzjH3fsm5OEI-NKY4dMmipor5EvQXRB6rPEjY,522
|
171
171
|
prefect/settings/sources.py,sha256=qoRt-XwfDB6-rC1UeZxF08G5DzpEtIU66mtm5fI7dP8,12676
|
172
172
|
prefect/settings/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
173
|
-
prefect/settings/models/api.py,sha256=
|
173
|
+
prefect/settings/models/api.py,sha256=nAT0Szkv0cknCPjetTrKpN10x9xsHJYyQExStwN-hhs,1709
|
174
174
|
prefect/settings/models/cli.py,sha256=mHB-BHBVO9qfQcr9uHbBmU6MMDLlLUUDxjyaRz7v1ls,958
|
175
175
|
prefect/settings/models/client.py,sha256=Ua18wKXWrNi0Ktb6cd42kdSOQYhFnObwTHTc3QDYg2k,2985
|
176
176
|
prefect/settings/models/cloud.py,sha256=7-WtW0rGPMOuG1O9Lwv_H_keEldXPo9YGHmoGwCXpeg,1767
|
@@ -181,12 +181,12 @@ prefect/settings/models/internal.py,sha256=mJ7h3d_WHw-0FBVhIbDHPjYI041YtuReD1bZO
|
|
181
181
|
prefect/settings/models/logging.py,sha256=YxD8fOcWOROUrq6dH6EIadJwYL7LlLSUGWlHVLn-l3Y,4560
|
182
182
|
prefect/settings/models/results.py,sha256=lU-3oVlgxGradSB1EYU-VZogK-rzE5LDw_wOcKhJp4M,1397
|
183
183
|
prefect/settings/models/root.py,sha256=7PC_Oiz7SYM3Ea3rqn_XnozvdivNq3rKc2dEcjTA5L4,16377
|
184
|
-
prefect/settings/models/runner.py,sha256=
|
184
|
+
prefect/settings/models/runner.py,sha256=eDS7CrO5NpngLhPIyzZuNoR5H4egoqvHLjOQKAT-MOM,1861
|
185
185
|
prefect/settings/models/tasks.py,sha256=qXLWJIVZT4L1GQcaCD_NUJktpB5WYOxthOq_PDLdj20,3309
|
186
186
|
prefect/settings/models/testing.py,sha256=r6KCYi8nvflCEwRFqS2T5J9baMHtVJfW0Q8EWARu1PQ,1733
|
187
187
|
prefect/settings/models/worker.py,sha256=EvaKk4j37QJw8o9w78kU9EF3dxx3aeHD4iT9shY3djk,1229
|
188
188
|
prefect/settings/models/server/__init__.py,sha256=KJmffmlHb8GYnClaeYcerae-IaeNsNMucKKRRS_zG9Q,33
|
189
|
-
prefect/settings/models/server/api.py,sha256=
|
189
|
+
prefect/settings/models/server/api.py,sha256=SLnHmsuwwqOPI5kgeOZR5dP0vscD9OzU13NsXIsWN2I,4972
|
190
190
|
prefect/settings/models/server/database.py,sha256=0eerMb05A9wD9_C4SefTzVvmba3rW18K2eteL2IcXLg,7201
|
191
191
|
prefect/settings/models/server/deployments.py,sha256=_GcxGOsMMrCzGEnOwC2i6JQW77h2tbyAdBJzAigHDas,778
|
192
192
|
prefect/settings/models/server/ephemeral.py,sha256=WxSpF-z9iDKAEjvcqrA5aggLEPRbl_ERocoLxPlu424,923
|
@@ -240,8 +240,8 @@ prefect/workers/cloud.py,sha256=BOVVY5z-vUIQ2u8LwMTXDaNys2fjOZSS5YGDwJmTQjI,230
|
|
240
240
|
prefect/workers/process.py,sha256=tcJ3fbiraLCfpVGpv8dOHwMSfVzeD_kyguUOvPuIz6I,19796
|
241
241
|
prefect/workers/server.py,sha256=lgh2FfSuaNU7b6HPxSFm8JtKvAvHsZGkiOo4y4tW1Cw,2022
|
242
242
|
prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
|
243
|
-
prefect_client-3.1.
|
244
|
-
prefect_client-3.1.
|
245
|
-
prefect_client-3.1.
|
246
|
-
prefect_client-3.1.
|
247
|
-
prefect_client-3.1.
|
243
|
+
prefect_client-3.1.8.dist-info/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
244
|
+
prefect_client-3.1.8.dist-info/METADATA,sha256=4KfLwSINwbcWgsBb4RwSbu-lz7FjcGvGCoiKQ3a04_E,7286
|
245
|
+
prefect_client-3.1.8.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
246
|
+
prefect_client-3.1.8.dist-info/top_level.txt,sha256=MJZYJgFdbRc2woQCeB4vM6T33tr01TmkEhRcns6H_H4,8
|
247
|
+
prefect_client-3.1.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|