prefect-client 3.0.0rc10__py3-none-any.whl → 3.0.0rc11__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/runner/server.py CHANGED
@@ -16,7 +16,6 @@ from prefect.runner.utils import (
16
16
  inject_schemas_into_openapi,
17
17
  )
18
18
  from prefect.settings import (
19
- PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS,
20
19
  PREFECT_RUNNER_POLL_FREQUENCY,
21
20
  PREFECT_RUNNER_SERVER_HOST,
22
21
  PREFECT_RUNNER_SERVER_LOG_LEVEL,
@@ -202,7 +201,7 @@ def _build_generic_endpoint_for_flows(
202
201
 
203
202
  try:
204
203
  flow = load_flow_from_entrypoint(body.entrypoint)
205
- except (MissingFlowError, ScriptError, ModuleNotFoundError):
204
+ except (FileNotFoundError, MissingFlowError, ScriptError, ModuleNotFoundError):
206
205
  return JSONResponse(
207
206
  status_code=status.HTTP_404_NOT_FOUND,
208
207
  content={"message": "Flow not found"},
@@ -261,29 +260,28 @@ async def build_server(runner: "Runner") -> FastAPI:
261
260
  router.add_api_route("/shutdown", shutdown(runner=runner), methods=["POST"])
262
261
  webserver.include_router(router)
263
262
 
264
- if PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS.value():
265
- deployments_router, deployment_schemas = await get_deployment_router(runner)
266
- webserver.include_router(deployments_router)
267
-
268
- subflow_schemas = await get_subflow_schemas(runner)
269
- webserver.add_api_route(
270
- "/flow/run",
271
- _build_generic_endpoint_for_flows(runner=runner, schemas=subflow_schemas),
272
- methods=["POST"],
273
- name="Run flow in background",
274
- description="Trigger any flow run as a background task on the runner.",
275
- summary="Run flow",
276
- )
277
-
278
- def customize_openapi():
279
- if webserver.openapi_schema:
280
- return webserver.openapi_schema
263
+ deployments_router, deployment_schemas = await get_deployment_router(runner)
264
+ webserver.include_router(deployments_router)
265
+
266
+ subflow_schemas = await get_subflow_schemas(runner)
267
+ webserver.add_api_route(
268
+ "/flow/run",
269
+ _build_generic_endpoint_for_flows(runner=runner, schemas=subflow_schemas),
270
+ methods=["POST"],
271
+ name="Run flow in background",
272
+ description="Trigger any flow run as a background task on the runner.",
273
+ summary="Run flow",
274
+ )
281
275
 
282
- openapi_schema = inject_schemas_into_openapi(webserver, deployment_schemas)
283
- webserver.openapi_schema = openapi_schema
276
+ def customize_openapi():
277
+ if webserver.openapi_schema:
284
278
  return webserver.openapi_schema
285
279
 
286
- webserver.openapi = customize_openapi
280
+ openapi_schema = inject_schemas_into_openapi(webserver, deployment_schemas)
281
+ webserver.openapi_schema = openapi_schema
282
+ return webserver.openapi_schema
283
+
284
+ webserver.openapi = customize_openapi
287
285
 
288
286
  return webserver
289
287
 
prefect/runner/submit.py CHANGED
@@ -14,7 +14,6 @@ from prefect.context import FlowRunContext
14
14
  from prefect.flows import Flow
15
15
  from prefect.logging import get_logger
16
16
  from prefect.settings import (
17
- PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS,
18
17
  PREFECT_RUNNER_PROCESS_LIMIT,
19
18
  PREFECT_RUNNER_SERVER_HOST,
20
19
  PREFECT_RUNNER_SERVER_PORT,
@@ -131,13 +130,6 @@ async def submit_to_runner(
131
130
  "The `submit_to_runner` utility only supports submitting flows and tasks."
132
131
  )
133
132
 
134
- if not PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS.value():
135
- raise ValueError(
136
- "The `submit_to_runner` utility requires the `Runner` webserver to be"
137
- " running and built with extra endpoints enabled. To enable this, set the"
138
- " `PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS` setting to `True`."
139
- )
140
-
141
133
  parameters = parameters or {}
142
134
  if isinstance(parameters, List):
143
135
  return_single = False
@@ -38,6 +38,7 @@ __all__ = [
38
38
  "parameters",
39
39
  "parent_flow_run_id",
40
40
  "parent_deployment_id",
41
+ "root_flow_run_id",
41
42
  "run_count",
42
43
  "api_url",
43
44
  "ui_url",
@@ -237,11 +238,12 @@ def get_parent_flow_run_id() -> Optional[str]:
237
238
  parent_task_run = from_sync.call_soon_in_loop_thread(
238
239
  create_call(_get_task_run, parent_task_run_id)
239
240
  ).result()
240
- return parent_task_run.flow_run_id
241
+ return str(parent_task_run.flow_run_id) if parent_task_run.flow_run_id else None
242
+
241
243
  return None
242
244
 
243
245
 
244
- def get_parent_deployment_id() -> Dict[str, Any]:
246
+ def get_parent_deployment_id() -> Optional[str]:
245
247
  parent_flow_run_id = get_parent_flow_run_id()
246
248
  if parent_flow_run_id is None:
247
249
  return None
@@ -249,7 +251,39 @@ def get_parent_deployment_id() -> Dict[str, Any]:
249
251
  parent_flow_run = from_sync.call_soon_in_loop_thread(
250
252
  create_call(_get_flow_run, parent_flow_run_id)
251
253
  ).result()
252
- return parent_flow_run.deployment_id if parent_flow_run else None
254
+
255
+ if parent_flow_run:
256
+ return (
257
+ str(parent_flow_run.deployment_id)
258
+ if parent_flow_run.deployment_id
259
+ else None
260
+ )
261
+
262
+ return None
263
+
264
+
265
+ def get_root_flow_run_id() -> str:
266
+ run_id = get_id()
267
+ parent_flow_run_id = get_parent_flow_run_id()
268
+ if parent_flow_run_id is None:
269
+ return run_id
270
+
271
+ def _get_root_flow_run_id(flow_run_id):
272
+ flow_run = from_sync.call_soon_in_loop_thread(
273
+ create_call(_get_flow_run, flow_run_id)
274
+ ).result()
275
+
276
+ if flow_run.parent_task_run_id is None:
277
+ return str(flow_run_id)
278
+ else:
279
+ parent_task_run = from_sync.call_soon_in_loop_thread(
280
+ create_call(_get_task_run, flow_run.parent_task_run_id)
281
+ ).result()
282
+ return _get_root_flow_run_id(parent_task_run.flow_run_id)
283
+
284
+ root_flow_run_id = _get_root_flow_run_id(parent_flow_run_id)
285
+
286
+ return root_flow_run_id
253
287
 
254
288
 
255
289
  def get_flow_run_api_url() -> Optional[str]:
@@ -275,6 +309,7 @@ FIELDS = {
275
309
  "parameters": get_parameters,
276
310
  "parent_flow_run_id": get_parent_flow_run_id,
277
311
  "parent_deployment_id": get_parent_deployment_id,
312
+ "root_flow_run_id": get_root_flow_run_id,
278
313
  "run_count": get_run_count,
279
314
  "api_url": get_flow_run_api_url,
280
315
  "ui_url": get_flow_run_ui_url,
prefect/settings.py CHANGED
@@ -1160,6 +1160,11 @@ polled."""
1160
1160
  PREFECT_API_LOG_RETRYABLE_ERRORS = Setting(bool, default=False)
1161
1161
  """If `True`, log retryable errors in the API and it's services."""
1162
1162
 
1163
+ PREFECT_API_SERVICES_TASK_RUN_RECORDER_ENABLED = Setting(bool, default=True)
1164
+ """
1165
+ Whether or not to start the task run recorder service in the server application.
1166
+ """
1167
+
1163
1168
 
1164
1169
  PREFECT_API_DEFAULT_LIMIT = Setting(
1165
1170
  int,
@@ -1309,17 +1314,13 @@ The maximum number of artifacts to show on a flow run graph on the v2 API
1309
1314
  """
1310
1315
 
1311
1316
 
1312
- PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_CANCELLATION = Setting(bool, default=True)
1313
- """
1314
- Whether or not to enable experimental enhanced flow run cancellation.
1315
- """
1316
-
1317
- PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION = Setting(bool, default=False)
1317
+ PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION = Setting(
1318
+ bool, default=False
1319
+ )
1318
1320
  """
1319
- Whether or not to warn when experimental enhanced flow run cancellation is used.
1321
+ Whether or not to enable experimental client side task run orchestration.
1320
1322
  """
1321
1323
 
1322
-
1323
1324
  # Prefect Events feature flags
1324
1325
 
1325
1326
  PREFECT_RUNNER_PROCESS_LIMIT = Setting(int, default=5)
@@ -1437,11 +1438,6 @@ a task worker should move a task from PENDING to RUNNING very quickly, so runs s
1437
1438
  PENDING for a while is a sign that the task worker may have crashed.
1438
1439
  """
1439
1440
 
1440
- PREFECT_EXPERIMENTAL_ENABLE_EXTRA_RUNNER_ENDPOINTS = Setting(bool, default=False)
1441
- """
1442
- Whether or not to enable experimental worker webserver endpoints.
1443
- """
1444
-
1445
1441
  PREFECT_EXPERIMENTAL_DISABLE_SYNC_COMPAT = Setting(bool, default=False)
1446
1442
  """
1447
1443
  Whether or not to disable the sync_compatible decorator utility.
prefect/task_worker.py CHANGED
@@ -325,7 +325,7 @@ class TaskWorker:
325
325
 
326
326
  if task_run_url := url_for(task_run):
327
327
  logger.info(
328
- f"Submitting task run {task_run.name!r} to engine. View run in the UI at {task_run_url!r}"
328
+ f"Submitting task run {task_run.name!r} to engine. View in the UI: {task_run_url}"
329
329
  )
330
330
 
331
331
  if task.isasync:
prefect/transactions.py CHANGED
@@ -187,8 +187,16 @@ class Transaction(ContextModel):
187
187
 
188
188
  for hook in self.on_commit_hooks:
189
189
  hook_name = _get_hook_name(hook)
190
+ if self.logger:
191
+ self.logger.info(f"Running commit hook {hook_name!r}")
192
+
190
193
  hook(self)
191
194
 
195
+ if self.logger:
196
+ self.logger.info(
197
+ f"Commit hook {hook_name!r} finished running successfully"
198
+ )
199
+
192
200
  if self.store and self.key:
193
201
  self.store.write(key=self.key, value=self._staged_value)
194
202
  self.state = TransactionState.COMMITTED
@@ -235,8 +243,16 @@ class Transaction(ContextModel):
235
243
  try:
236
244
  for hook in reversed(self.on_rollback_hooks):
237
245
  hook_name = _get_hook_name(hook)
246
+ if self.logger:
247
+ self.logger.info(f"Running rollback hook {hook_name!r}")
248
+
238
249
  hook(self)
239
250
 
251
+ if self.logger:
252
+ self.logger.info(
253
+ f"Rollback hook {hook_name!r} finished running successfully"
254
+ )
255
+
240
256
  self.state = TransactionState.ROLLED_BACK
241
257
 
242
258
  for child in reversed(self.children):
@@ -249,6 +249,7 @@ def run_coro_as_sync(
249
249
  return call.result()
250
250
  except KeyboardInterrupt:
251
251
  call.cancel()
252
+
252
253
  logger.debug("Coroutine cancelled due to KeyboardInterrupt.")
253
254
  raise
254
255
 
@@ -51,6 +51,7 @@ from prefect.logging.loggers import (
51
51
  )
52
52
  from prefect.results import BaseResult
53
53
  from prefect.settings import (
54
+ PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION,
54
55
  PREFECT_LOGGING_LOG_PRINTS,
55
56
  )
56
57
  from prefect.states import (
@@ -558,7 +559,7 @@ def propose_state_sync(
558
559
  )
559
560
 
560
561
 
561
- def _dynamic_key_for_task_run(context: FlowRunContext, task: Task) -> int:
562
+ def _dynamic_key_for_task_run(context: FlowRunContext, task: Task) -> Union[int, str]:
562
563
  if context.detached: # this task is running on remote infrastructure
563
564
  return str(uuid4())
564
565
  elif context.flow_run is None: # this is an autonomous task run
@@ -744,6 +745,12 @@ def emit_task_run_state_change_event(
744
745
  "message": truncated_to(
745
746
  state_message_truncation_length, initial_state.message
746
747
  ),
748
+ "state_details": initial_state.state_details.model_dump(
749
+ mode="json",
750
+ exclude_none=True,
751
+ exclude_unset=True,
752
+ exclude={"flow_run_id", "task_run_id"},
753
+ ),
747
754
  }
748
755
  if initial_state
749
756
  else None
@@ -754,7 +761,30 @@ def emit_task_run_state_change_event(
754
761
  "message": truncated_to(
755
762
  state_message_truncation_length, validated_state.message
756
763
  ),
764
+ "state_details": validated_state.state_details.model_dump(
765
+ mode="json",
766
+ exclude_none=True,
767
+ exclude_unset=True,
768
+ exclude={"flow_run_id", "task_run_id"},
769
+ ),
770
+ "data": validated_state.data.model_dump(mode="json")
771
+ if isinstance(validated_state.data, BaseResult)
772
+ else None,
757
773
  },
774
+ "task_run": task_run.model_dump(
775
+ mode="json",
776
+ exclude_none=True,
777
+ exclude={
778
+ "id",
779
+ "created",
780
+ "updated",
781
+ "flow_run_id",
782
+ "state_id",
783
+ "state_type",
784
+ "state_name",
785
+ "state",
786
+ },
787
+ ),
758
788
  },
759
789
  resource={
760
790
  "prefect.resource.id": f"prefect.task-run.{task_run.id}",
@@ -769,6 +799,9 @@ def emit_task_run_state_change_event(
769
799
  else ""
770
800
  ),
771
801
  "prefect.state-type": str(validated_state.type.value),
802
+ "prefect.orchestration": "client"
803
+ if PREFECT_EXPERIMENTAL_ENABLE_CLIENT_SIDE_TASK_ORCHESTRATION
804
+ else "server",
772
805
  },
773
806
  follows=follows,
774
807
  )