prefect-client 3.1.15__py3-none-any.whl → 3.2.0__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/_experimental/sla/objects.py +29 -1
- prefect/_internal/compatibility/deprecated.py +4 -4
- prefect/_internal/compatibility/migration.py +1 -1
- prefect/_internal/concurrency/calls.py +1 -2
- prefect/_internal/concurrency/cancellation.py +2 -4
- prefect/_internal/concurrency/threads.py +3 -3
- prefect/_internal/schemas/bases.py +3 -11
- prefect/_internal/schemas/validators.py +36 -60
- prefect/_result_records.py +235 -0
- prefect/_version.py +3 -3
- prefect/agent.py +1 -0
- prefect/automations.py +4 -8
- prefect/blocks/notifications.py +8 -8
- prefect/cache_policies.py +2 -0
- prefect/client/base.py +7 -8
- prefect/client/collections.py +3 -6
- prefect/client/orchestration/__init__.py +15 -263
- prefect/client/orchestration/_deployments/client.py +14 -6
- prefect/client/orchestration/_flow_runs/client.py +10 -6
- prefect/client/orchestration/_work_pools/__init__.py +0 -0
- prefect/client/orchestration/_work_pools/client.py +598 -0
- prefect/client/orchestration/base.py +9 -2
- prefect/client/schemas/actions.py +66 -2
- prefect/client/schemas/objects.py +22 -50
- prefect/client/schemas/schedules.py +7 -18
- prefect/client/types/flexible_schedule_list.py +2 -1
- prefect/context.py +2 -3
- prefect/deployments/flow_runs.py +1 -1
- prefect/deployments/runner.py +119 -43
- prefect/deployments/schedules.py +7 -1
- prefect/engine.py +4 -9
- prefect/events/schemas/automations.py +4 -2
- prefect/events/utilities.py +15 -13
- prefect/exceptions.py +1 -1
- prefect/flow_engine.py +8 -8
- prefect/flow_runs.py +4 -8
- prefect/flows.py +30 -22
- prefect/infrastructure/__init__.py +1 -0
- prefect/infrastructure/base.py +1 -0
- prefect/infrastructure/provisioners/__init__.py +3 -6
- prefect/infrastructure/provisioners/coiled.py +3 -3
- prefect/infrastructure/provisioners/container_instance.py +1 -0
- prefect/infrastructure/provisioners/ecs.py +6 -6
- prefect/infrastructure/provisioners/modal.py +3 -3
- prefect/input/run_input.py +5 -7
- prefect/locking/filesystem.py +4 -3
- prefect/main.py +1 -1
- prefect/results.py +42 -249
- prefect/runner/runner.py +9 -4
- prefect/runner/server.py +5 -5
- prefect/runner/storage.py +12 -10
- prefect/runner/submit.py +2 -4
- prefect/schedules.py +231 -0
- prefect/serializers.py +5 -5
- prefect/settings/__init__.py +2 -1
- prefect/settings/base.py +3 -3
- prefect/settings/models/root.py +4 -0
- prefect/settings/models/server/services.py +50 -9
- prefect/settings/sources.py +4 -4
- prefect/states.py +42 -11
- prefect/task_engine.py +10 -10
- prefect/task_runners.py +11 -22
- prefect/task_worker.py +9 -9
- prefect/tasks.py +22 -41
- prefect/telemetry/bootstrap.py +4 -6
- prefect/telemetry/services.py +2 -4
- prefect/types/__init__.py +2 -1
- prefect/types/_datetime.py +28 -1
- prefect/utilities/_engine.py +0 -1
- prefect/utilities/asyncutils.py +4 -8
- prefect/utilities/collections.py +13 -22
- prefect/utilities/dispatch.py +2 -4
- prefect/utilities/dockerutils.py +6 -6
- prefect/utilities/importtools.py +1 -68
- prefect/utilities/names.py +1 -1
- prefect/utilities/processutils.py +3 -6
- prefect/utilities/pydantic.py +4 -6
- prefect/utilities/schema_tools/hydration.py +6 -5
- prefect/utilities/templating.py +16 -10
- prefect/utilities/visualization.py +2 -4
- prefect/workers/base.py +3 -3
- prefect/workers/block.py +1 -0
- prefect/workers/cloud.py +1 -0
- prefect/workers/process.py +1 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/METADATA +1 -1
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/RECORD +89 -85
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/top_level.txt +0 -0
prefect/deployments/runner.py
CHANGED
@@ -57,7 +57,7 @@ from prefect._internal.schemas.validators import (
|
|
57
57
|
)
|
58
58
|
from prefect.client.base import ServerType
|
59
59
|
from prefect.client.orchestration import PrefectClient, get_client
|
60
|
-
from prefect.client.schemas.actions import DeploymentScheduleCreate
|
60
|
+
from prefect.client.schemas.actions import DeploymentScheduleCreate, DeploymentUpdate
|
61
61
|
from prefect.client.schemas.filters import WorkerFilter, WorkerFilterStatus
|
62
62
|
from prefect.client.schemas.objects import (
|
63
63
|
ConcurrencyLimitConfig,
|
@@ -77,6 +77,7 @@ from prefect.exceptions import (
|
|
77
77
|
PrefectHTTPStatusError,
|
78
78
|
)
|
79
79
|
from prefect.runner.storage import RunnerStorage
|
80
|
+
from prefect.schedules import Schedule
|
80
81
|
from prefect.settings import (
|
81
82
|
PREFECT_DEFAULT_WORK_POOL_NAME,
|
82
83
|
PREFECT_UI_URL,
|
@@ -113,7 +114,7 @@ class RunnerDeployment(BaseModel):
|
|
113
114
|
description: An optional description of the deployment; defaults to the flow's
|
114
115
|
description
|
115
116
|
tags: An optional list of tags to associate with this deployment; note that tags
|
116
|
-
are used only for organizational purposes. For delegating work to
|
117
|
+
are used only for organizational purposes. For delegating work to workers,
|
117
118
|
see `work_queue_name`.
|
118
119
|
schedule: A schedule to run this deployment on, once registered
|
119
120
|
parameters: A dictionary of parameter values to pass to runs created from this
|
@@ -229,6 +230,10 @@ class RunnerDeployment(BaseModel):
|
|
229
230
|
def entrypoint_type(self) -> EntrypointType:
|
230
231
|
return self._entrypoint_type
|
231
232
|
|
233
|
+
@property
|
234
|
+
def full_name(self) -> str:
|
235
|
+
return f"{self.flow_name}/{self.name}"
|
236
|
+
|
232
237
|
@field_validator("name", mode="before")
|
233
238
|
@classmethod
|
234
239
|
def validate_name(cls, value: str) -> str:
|
@@ -255,24 +260,9 @@ class RunnerDeployment(BaseModel):
|
|
255
260
|
def reconcile_schedules(cls, values):
|
256
261
|
return reconcile_schedules_runner(values)
|
257
262
|
|
258
|
-
|
259
|
-
async def apply(
|
263
|
+
async def _create(
|
260
264
|
self, work_pool_name: Optional[str] = None, image: Optional[str] = None
|
261
265
|
) -> UUID:
|
262
|
-
"""
|
263
|
-
Registers this deployment with the API and returns the deployment's ID.
|
264
|
-
|
265
|
-
Args:
|
266
|
-
work_pool_name: The name of the work pool to use for this
|
267
|
-
deployment.
|
268
|
-
image: The registry, name, and tag of the Docker image to
|
269
|
-
use for this deployment. Only used when the deployment is
|
270
|
-
deployed to a work pool.
|
271
|
-
|
272
|
-
Returns:
|
273
|
-
The ID of the created deployment.
|
274
|
-
"""
|
275
|
-
|
276
266
|
work_pool_name = work_pool_name or self.work_pool_name
|
277
267
|
|
278
268
|
if image and not work_pool_name:
|
@@ -324,9 +314,14 @@ class RunnerDeployment(BaseModel):
|
|
324
314
|
if image:
|
325
315
|
create_payload["job_variables"]["image"] = image
|
326
316
|
create_payload["path"] = None if self.storage else self._path
|
327
|
-
|
328
|
-
|
329
|
-
|
317
|
+
if self.storage:
|
318
|
+
pull_steps = self.storage.to_pull_step()
|
319
|
+
if isinstance(pull_steps, list):
|
320
|
+
create_payload["pull_steps"] = pull_steps
|
321
|
+
else:
|
322
|
+
create_payload["pull_steps"] = [pull_steps]
|
323
|
+
else:
|
324
|
+
create_payload["pull_steps"] = []
|
330
325
|
|
331
326
|
try:
|
332
327
|
deployment_id = await client.create_deployment(**create_payload)
|
@@ -339,25 +334,7 @@ class RunnerDeployment(BaseModel):
|
|
339
334
|
f"Error while applying deployment: {str(exc)}"
|
340
335
|
) from exc
|
341
336
|
|
342
|
-
|
343
|
-
# The triggers defined in the deployment spec are, essentially,
|
344
|
-
# anonymous and attempting truly sync them with cloud is not
|
345
|
-
# feasible. Instead, we remove all automations that are owned
|
346
|
-
# by the deployment, meaning that they were created via this
|
347
|
-
# mechanism below, and then recreate them.
|
348
|
-
await client.delete_resource_owned_automations(
|
349
|
-
f"prefect.deployment.{deployment_id}"
|
350
|
-
)
|
351
|
-
except PrefectHTTPStatusError as e:
|
352
|
-
if e.response.status_code == 404:
|
353
|
-
# This Prefect server does not support automations, so we can safely
|
354
|
-
# ignore this 404 and move on.
|
355
|
-
return deployment_id
|
356
|
-
raise e
|
357
|
-
|
358
|
-
for trigger in self.triggers:
|
359
|
-
trigger.set_deployment_id(deployment_id)
|
360
|
-
await client.create_automation(trigger.as_automation())
|
337
|
+
await self._create_triggers(deployment_id, client)
|
361
338
|
|
362
339
|
# We plan to support SLA configuration on the Prefect Server in the future.
|
363
340
|
# For now, we only support it on Prefect Cloud.
|
@@ -370,6 +347,86 @@ class RunnerDeployment(BaseModel):
|
|
370
347
|
|
371
348
|
return deployment_id
|
372
349
|
|
350
|
+
async def _update(self, deployment_id: UUID, client: PrefectClient):
|
351
|
+
parameter_openapi_schema = self._parameter_openapi_schema.model_dump(
|
352
|
+
exclude_unset=True
|
353
|
+
)
|
354
|
+
await client.update_deployment(
|
355
|
+
deployment_id,
|
356
|
+
deployment=DeploymentUpdate(
|
357
|
+
parameter_openapi_schema=parameter_openapi_schema,
|
358
|
+
**self.model_dump(
|
359
|
+
mode="json",
|
360
|
+
exclude_unset=True,
|
361
|
+
exclude={"storage", "name", "flow_name", "triggers"},
|
362
|
+
),
|
363
|
+
),
|
364
|
+
)
|
365
|
+
|
366
|
+
await self._create_triggers(deployment_id, client)
|
367
|
+
|
368
|
+
# We plan to support SLA configuration on the Prefect Server in the future.
|
369
|
+
# For now, we only support it on Prefect Cloud.
|
370
|
+
|
371
|
+
# If we're provided with an empty list, we will call the apply endpoint
|
372
|
+
# to remove existing SLAs for the deployment. If the argument is not provided,
|
373
|
+
# we will not call the endpoint.
|
374
|
+
if self._sla or self._sla == []:
|
375
|
+
await self._create_slas(deployment_id, client)
|
376
|
+
|
377
|
+
return deployment_id
|
378
|
+
|
379
|
+
async def _create_triggers(self, deployment_id: UUID, client: PrefectClient):
|
380
|
+
try:
|
381
|
+
# The triggers defined in the deployment spec are, essentially,
|
382
|
+
# anonymous and attempting truly sync them with cloud is not
|
383
|
+
# feasible. Instead, we remove all automations that are owned
|
384
|
+
# by the deployment, meaning that they were created via this
|
385
|
+
# mechanism below, and then recreate them.
|
386
|
+
await client.delete_resource_owned_automations(
|
387
|
+
f"prefect.deployment.{deployment_id}"
|
388
|
+
)
|
389
|
+
except PrefectHTTPStatusError as e:
|
390
|
+
if e.response.status_code == 404:
|
391
|
+
# This Prefect server does not support automations, so we can safely
|
392
|
+
# ignore this 404 and move on.
|
393
|
+
return deployment_id
|
394
|
+
raise e
|
395
|
+
|
396
|
+
for trigger in self.triggers:
|
397
|
+
trigger.set_deployment_id(deployment_id)
|
398
|
+
await client.create_automation(trigger.as_automation())
|
399
|
+
|
400
|
+
@sync_compatible
|
401
|
+
async def apply(
|
402
|
+
self, work_pool_name: Optional[str] = None, image: Optional[str] = None
|
403
|
+
) -> UUID:
|
404
|
+
"""
|
405
|
+
Registers this deployment with the API and returns the deployment's ID.
|
406
|
+
|
407
|
+
Args:
|
408
|
+
work_pool_name: The name of the work pool to use for this
|
409
|
+
deployment.
|
410
|
+
image: The registry, name, and tag of the Docker image to
|
411
|
+
use for this deployment. Only used when the deployment is
|
412
|
+
deployed to a work pool.
|
413
|
+
|
414
|
+
Returns:
|
415
|
+
The ID of the created deployment.
|
416
|
+
"""
|
417
|
+
|
418
|
+
async with get_client() as client:
|
419
|
+
try:
|
420
|
+
deployment = await client.read_deployment_by_name(self.full_name)
|
421
|
+
except ObjectNotFound:
|
422
|
+
return await self._create(work_pool_name, image)
|
423
|
+
else:
|
424
|
+
if image:
|
425
|
+
self.job_variables["image"] = image
|
426
|
+
if work_pool_name:
|
427
|
+
self.work_pool_name = work_pool_name
|
428
|
+
return await self._update(deployment.id, client)
|
429
|
+
|
373
430
|
async def _create_slas(self, deployment_id: UUID, client: PrefectClient):
|
374
431
|
if not isinstance(self._sla, list):
|
375
432
|
self._sla = [self._sla]
|
@@ -390,7 +447,7 @@ class RunnerDeployment(BaseModel):
|
|
390
447
|
cron: Optional[Union[Iterable[str], str]] = None,
|
391
448
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
392
449
|
timezone: Optional[str] = None,
|
393
|
-
schedule:
|
450
|
+
schedule: Union[SCHEDULE_TYPES, Schedule, None] = None,
|
394
451
|
schedules: Optional["FlexibleScheduleList"] = None,
|
395
452
|
) -> Union[List[DeploymentScheduleCreate], "FlexibleScheduleList"]:
|
396
453
|
"""
|
@@ -422,7 +479,6 @@ class RunnerDeployment(BaseModel):
|
|
422
479
|
this list is returned as-is, bypassing other schedule construction
|
423
480
|
logic.
|
424
481
|
"""
|
425
|
-
|
426
482
|
num_schedules = sum(
|
427
483
|
1
|
428
484
|
for entry in (interval, cron, rrule, schedule, schedules)
|
@@ -430,7 +486,7 @@ class RunnerDeployment(BaseModel):
|
|
430
486
|
)
|
431
487
|
if num_schedules > 1:
|
432
488
|
raise ValueError(
|
433
|
-
"Only one of interval, cron, rrule, or schedules can be provided."
|
489
|
+
"Only one of interval, cron, rrule, schedule, or schedules can be provided."
|
434
490
|
)
|
435
491
|
elif num_schedules == 0:
|
436
492
|
return []
|
@@ -483,6 +539,7 @@ class RunnerDeployment(BaseModel):
|
|
483
539
|
cron: Optional[Union[Iterable[str], str]] = None,
|
484
540
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
485
541
|
paused: Optional[bool] = None,
|
542
|
+
schedule: Optional[Schedule] = None,
|
486
543
|
schedules: Optional["FlexibleScheduleList"] = None,
|
487
544
|
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
488
545
|
parameters: Optional[dict[str, Any]] = None,
|
@@ -508,6 +565,8 @@ class RunnerDeployment(BaseModel):
|
|
508
565
|
cron: A cron schedule of when to execute runs of this flow.
|
509
566
|
rrule: An rrule schedule of when to execute runs of this flow.
|
510
567
|
paused: Whether or not to set this deployment as paused.
|
568
|
+
schedule: A schedule object defining when to execute runs of this deployment.
|
569
|
+
Used to provide additional scheduling options like `timezone` or `parameters`.
|
511
570
|
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
512
571
|
Used to define multiple schedules or additional scheduling options like `timezone`.
|
513
572
|
concurrency_limit: The maximum number of concurrent runs this deployment will allow.
|
@@ -533,6 +592,7 @@ class RunnerDeployment(BaseModel):
|
|
533
592
|
cron=cron,
|
534
593
|
rrule=rrule,
|
535
594
|
schedules=schedules,
|
595
|
+
schedule=schedule,
|
536
596
|
)
|
537
597
|
|
538
598
|
job_variables = job_variables or {}
|
@@ -627,6 +687,7 @@ class RunnerDeployment(BaseModel):
|
|
627
687
|
cron: Optional[Union[Iterable[str], str]] = None,
|
628
688
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
629
689
|
paused: Optional[bool] = None,
|
690
|
+
schedule: Optional[Schedule] = None,
|
630
691
|
schedules: Optional["FlexibleScheduleList"] = None,
|
631
692
|
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
632
693
|
parameters: Optional[dict[str, Any]] = None,
|
@@ -682,6 +743,7 @@ class RunnerDeployment(BaseModel):
|
|
682
743
|
cron=cron,
|
683
744
|
rrule=rrule,
|
684
745
|
schedules=schedules,
|
746
|
+
schedule=schedule,
|
685
747
|
)
|
686
748
|
|
687
749
|
if isinstance(concurrency_limit, ConcurrencyLimitConfig):
|
@@ -730,6 +792,7 @@ class RunnerDeployment(BaseModel):
|
|
730
792
|
cron: Optional[Union[Iterable[str], str]] = None,
|
731
793
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
732
794
|
paused: Optional[bool] = None,
|
795
|
+
schedule: Optional[Schedule] = None,
|
733
796
|
schedules: Optional["FlexibleScheduleList"] = None,
|
734
797
|
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
735
798
|
parameters: Optional[dict[str, Any]] = None,
|
@@ -758,6 +821,11 @@ class RunnerDeployment(BaseModel):
|
|
758
821
|
or a timedelta object. If a number is given, it will be interpreted as seconds.
|
759
822
|
cron: A cron schedule of when to execute runs of this flow.
|
760
823
|
rrule: An rrule schedule of when to execute runs of this flow.
|
824
|
+
paused: Whether or not the deployment is paused.
|
825
|
+
schedule: A schedule object defining when to execute runs of this deployment.
|
826
|
+
Used to provide additional scheduling options like `timezone` or `parameters`.
|
827
|
+
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
828
|
+
Used to provide additional scheduling options like `timezone` or `parameters`.
|
761
829
|
triggers: A list of triggers that should kick of a run of this flow.
|
762
830
|
parameters: A dictionary of default parameter values to pass to runs of this flow.
|
763
831
|
description: A description for the created deployment. Defaults to the flow's
|
@@ -782,6 +850,7 @@ class RunnerDeployment(BaseModel):
|
|
782
850
|
cron=cron,
|
783
851
|
rrule=rrule,
|
784
852
|
schedules=schedules,
|
853
|
+
schedule=schedule,
|
785
854
|
)
|
786
855
|
|
787
856
|
if isinstance(concurrency_limit, ConcurrencyLimitConfig):
|
@@ -845,6 +914,7 @@ class RunnerDeployment(BaseModel):
|
|
845
914
|
cron: Optional[Union[Iterable[str], str]] = None,
|
846
915
|
rrule: Optional[Union[Iterable[str], str]] = None,
|
847
916
|
paused: Optional[bool] = None,
|
917
|
+
schedule: Optional[Schedule] = None,
|
848
918
|
schedules: Optional["FlexibleScheduleList"] = None,
|
849
919
|
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
850
920
|
parameters: Optional[dict[str, Any]] = None,
|
@@ -873,6 +943,11 @@ class RunnerDeployment(BaseModel):
|
|
873
943
|
or a timedelta object. If a number is given, it will be interpreted as seconds.
|
874
944
|
cron: A cron schedule of when to execute runs of this flow.
|
875
945
|
rrule: An rrule schedule of when to execute runs of this flow.
|
946
|
+
paused: Whether or not the deployment is paused.
|
947
|
+
schedule: A schedule object defining when to execute runs of this deployment.
|
948
|
+
Used to provide additional scheduling options like `timezone` or `parameters`.
|
949
|
+
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
950
|
+
Used to provide additional scheduling options like `timezone` or `parameters`.
|
876
951
|
triggers: A list of triggers that should kick of a run of this flow.
|
877
952
|
parameters: A dictionary of default parameter values to pass to runs of this flow.
|
878
953
|
description: A description for the created deployment. Defaults to the flow's
|
@@ -897,6 +972,7 @@ class RunnerDeployment(BaseModel):
|
|
897
972
|
cron=cron,
|
898
973
|
rrule=rrule,
|
899
974
|
schedules=schedules,
|
975
|
+
schedule=schedule,
|
900
976
|
)
|
901
977
|
|
902
978
|
if isinstance(concurrency_limit, ConcurrencyLimitConfig):
|
prefect/deployments/schedules.py
CHANGED
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Union
|
|
2
2
|
|
3
3
|
from prefect.client.schemas.actions import DeploymentScheduleCreate
|
4
4
|
from prefect.client.schemas.schedules import is_schedule_type
|
5
|
+
from prefect.schedules import Schedule
|
5
6
|
|
6
7
|
if TYPE_CHECKING:
|
7
8
|
from prefect.client.schemas.schedules import SCHEDULE_TYPES
|
@@ -12,10 +13,13 @@ FlexibleScheduleList = Sequence[
|
|
12
13
|
|
13
14
|
|
14
15
|
def create_deployment_schedule_create(
|
15
|
-
schedule: "SCHEDULE_TYPES",
|
16
|
+
schedule: Union["SCHEDULE_TYPES", "Schedule"],
|
16
17
|
active: Optional[bool] = True,
|
17
18
|
) -> DeploymentScheduleCreate:
|
18
19
|
"""Create a DeploymentScheduleCreate object from common schedule parameters."""
|
20
|
+
|
21
|
+
if isinstance(schedule, Schedule):
|
22
|
+
return DeploymentScheduleCreate.from_schedule(schedule)
|
19
23
|
return DeploymentScheduleCreate(
|
20
24
|
schedule=schedule,
|
21
25
|
active=active if active is not None else True,
|
@@ -30,6 +34,8 @@ def normalize_to_deployment_schedule_create(
|
|
30
34
|
for obj in schedules:
|
31
35
|
if is_schedule_type(obj):
|
32
36
|
normalized.append(create_deployment_schedule_create(obj))
|
37
|
+
elif isinstance(obj, Schedule):
|
38
|
+
normalized.append(create_deployment_schedule_create(obj))
|
33
39
|
elif isinstance(obj, dict):
|
34
40
|
normalized.append(create_deployment_schedule_create(**obj))
|
35
41
|
elif isinstance(obj, DeploymentScheduleCreate):
|
prefect/engine.py
CHANGED
@@ -62,18 +62,13 @@ if __name__ == "__main__":
|
|
62
62
|
else:
|
63
63
|
run_flow(flow, flow_run=flow_run, error_logger=run_logger)
|
64
64
|
|
65
|
-
except Abort
|
66
|
-
abort_signal: Abort
|
65
|
+
except Abort:
|
67
66
|
engine_logger.info(
|
68
|
-
|
69
|
-
f" {abort_signal}"
|
67
|
+
"Engine execution of flow run '{flow_run_id}' aborted by orchestrator."
|
70
68
|
)
|
71
69
|
exit(0)
|
72
|
-
except Pause
|
73
|
-
|
74
|
-
engine_logger.info(
|
75
|
-
f"Engine execution of flow run '{flow_run_id}' is paused: {pause_signal}"
|
76
|
-
)
|
70
|
+
except Pause:
|
71
|
+
engine_logger.info(f"Engine execution of flow run '{flow_run_id}' is paused.")
|
77
72
|
exit(0)
|
78
73
|
except Exception:
|
79
74
|
engine_logger.error(
|
@@ -198,7 +198,9 @@ class EventTrigger(ResourceTrigger):
|
|
198
198
|
"10 seconds"
|
199
199
|
)
|
200
200
|
|
201
|
-
|
201
|
+
if within:
|
202
|
+
data = {**data, "within": within}
|
203
|
+
return data
|
202
204
|
|
203
205
|
def describe_for_cli(self, indent: int = 0) -> str:
|
204
206
|
"""Return a human-readable description of this trigger for the CLI"""
|
@@ -248,7 +250,7 @@ class MetricTriggerQuery(PrefectBaseModel):
|
|
248
250
|
threshold: float = Field(
|
249
251
|
...,
|
250
252
|
description=(
|
251
|
-
"The threshold value against which we'll compare
|
253
|
+
"The threshold value against which we'll compare the query result."
|
252
254
|
),
|
253
255
|
)
|
254
256
|
operator: MetricTriggerOperator = Field(
|
prefect/events/utilities.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from datetime import timedelta
|
2
|
-
from typing import Any
|
4
|
+
from typing import Any
|
3
5
|
from uuid import UUID
|
4
6
|
|
5
|
-
import
|
7
|
+
from prefect.types import DateTime
|
6
8
|
|
7
9
|
from .clients import (
|
8
10
|
AssertingEventsClient,
|
@@ -18,16 +20,16 @@ TIGHT_TIMING = timedelta(minutes=5)
|
|
18
20
|
|
19
21
|
def emit_event(
|
20
22
|
event: str,
|
21
|
-
resource:
|
22
|
-
occurred:
|
23
|
-
related:
|
24
|
-
payload:
|
25
|
-
id:
|
26
|
-
follows:
|
27
|
-
**kwargs:
|
28
|
-
) ->
|
23
|
+
resource: dict[str, str],
|
24
|
+
occurred: DateTime | None = None,
|
25
|
+
related: list[dict[str, str]] | list[RelatedResource] | None = None,
|
26
|
+
payload: dict[str, Any] | None = None,
|
27
|
+
id: UUID | None = None,
|
28
|
+
follows: Event | None = None,
|
29
|
+
**kwargs: dict[str, Any] | None,
|
30
|
+
) -> Event | None:
|
29
31
|
"""
|
30
|
-
Send an event to Prefect
|
32
|
+
Send an event to Prefect.
|
31
33
|
|
32
34
|
Args:
|
33
35
|
event: The name of the event that happened.
|
@@ -60,14 +62,14 @@ def emit_event(
|
|
60
62
|
if worker_instance.client_type not in operational_clients:
|
61
63
|
return None
|
62
64
|
|
63
|
-
event_kwargs:
|
65
|
+
event_kwargs: dict[str, Any] = {
|
64
66
|
"event": event,
|
65
67
|
"resource": resource,
|
66
68
|
**kwargs,
|
67
69
|
}
|
68
70
|
|
69
71
|
if occurred is None:
|
70
|
-
occurred =
|
72
|
+
occurred = DateTime.now("UTC")
|
71
73
|
event_kwargs["occurred"] = occurred
|
72
74
|
|
73
75
|
if related is not None:
|
prefect/exceptions.py
CHANGED
@@ -161,7 +161,7 @@ class ParameterTypeError(PrefectException):
|
|
161
161
|
@classmethod
|
162
162
|
def from_validation_error(cls, exc: ValidationError) -> Self:
|
163
163
|
bad_params = [
|
164
|
-
f'
|
164
|
+
f"{'.'.join(str(item) for item in err['loc'])}: {err['msg']}"
|
165
165
|
for err in exc.errors()
|
166
166
|
]
|
167
167
|
msg = "Flow run received invalid parameters:\n - " + "\n - ".join(bad_params)
|
prefect/flow_engine.py
CHANGED
@@ -1518,6 +1518,8 @@ def run_flow(
|
|
1518
1518
|
ret_val = run_flow_async(**kwargs)
|
1519
1519
|
else:
|
1520
1520
|
ret_val = run_flow_sync(**kwargs)
|
1521
|
+
except (Abort, Pause):
|
1522
|
+
raise
|
1521
1523
|
except:
|
1522
1524
|
if error_logger:
|
1523
1525
|
error_logger.error(
|
@@ -1597,20 +1599,18 @@ def run_flow_in_subprocess(
|
|
1597
1599
|
# This is running in a brand new process, so there won't be an existing
|
1598
1600
|
# event loop.
|
1599
1601
|
asyncio.run(maybe_coro)
|
1600
|
-
except Abort
|
1601
|
-
abort_signal: Abort
|
1602
|
+
except Abort:
|
1602
1603
|
if flow_run:
|
1603
|
-
msg = f"Execution of flow run '{flow_run.id}' aborted by orchestrator
|
1604
|
+
msg = f"Execution of flow run '{flow_run.id}' aborted by orchestrator."
|
1604
1605
|
else:
|
1605
|
-
msg =
|
1606
|
+
msg = "Execution aborted by orchestrator."
|
1606
1607
|
engine_logger.info(msg)
|
1607
1608
|
exit(0)
|
1608
|
-
except Pause
|
1609
|
-
pause_signal: Pause
|
1609
|
+
except Pause:
|
1610
1610
|
if flow_run:
|
1611
|
-
msg = f"Execution of flow run '{flow_run.id}' is paused
|
1611
|
+
msg = f"Execution of flow run '{flow_run.id}' is paused."
|
1612
1612
|
else:
|
1613
|
-
msg =
|
1613
|
+
msg = "Execution is paused."
|
1614
1614
|
engine_logger.info(msg)
|
1615
1615
|
exit(0)
|
1616
1616
|
except Exception:
|
prefect/flow_runs.py
CHANGED
@@ -139,8 +139,7 @@ async def pause_flow_run(
|
|
139
139
|
timeout: int = 3600,
|
140
140
|
poll_interval: int = 10,
|
141
141
|
key: Optional[str] = None,
|
142
|
-
) -> None:
|
143
|
-
...
|
142
|
+
) -> None: ...
|
144
143
|
|
145
144
|
|
146
145
|
@overload
|
@@ -149,8 +148,7 @@ async def pause_flow_run(
|
|
149
148
|
timeout: int = 3600,
|
150
149
|
poll_interval: int = 10,
|
151
150
|
key: Optional[str] = None,
|
152
|
-
) -> T:
|
153
|
-
...
|
151
|
+
) -> T: ...
|
154
152
|
|
155
153
|
|
156
154
|
@sync_compatible
|
@@ -308,8 +306,7 @@ async def suspend_flow_run(
|
|
308
306
|
timeout: Optional[int] = 3600,
|
309
307
|
key: Optional[str] = None,
|
310
308
|
client: Optional[PrefectClient] = None,
|
311
|
-
) -> None:
|
312
|
-
...
|
309
|
+
) -> None: ...
|
313
310
|
|
314
311
|
|
315
312
|
@overload
|
@@ -319,8 +316,7 @@ async def suspend_flow_run(
|
|
319
316
|
timeout: Optional[int] = 3600,
|
320
317
|
key: Optional[str] = None,
|
321
318
|
client: Optional[PrefectClient] = None,
|
322
|
-
) -> T:
|
323
|
-
...
|
319
|
+
) -> T: ...
|
324
320
|
|
325
321
|
|
326
322
|
@sync_compatible
|