Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions airflow-core/src/airflow/callbacks/callback_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
import structlog
from pydantic import BaseModel, Field, model_validator
from sqlalchemy import inspect as sa_inspect
from sqlalchemy.exc import NoInspectionAvailable
from sqlalchemy.exc import NoInspectionAvailable, SQLAlchemyError
from sqlalchemy.orm.attributes import set_committed_value
from sqlalchemy.orm.exc import DetachedInstanceError

from airflow.api_fastapi.execution_api.datamodels import taskinstance as ti_datamodel # noqa: TC001
from airflow.utils.state import TaskInstanceState
Expand Down Expand Up @@ -116,19 +115,20 @@ def _sanitize_consumed_asset_events(cls, values: Mapping[str, Any]) -> Mapping[s
except NoInspectionAvailable:
return values

# Relationship access may raise DetachedInstanceError; on that path, reload DagRun
# from the DB to avoid crashing the scheduler.
# Relationship access may raise DetachedInstanceError or other SQLAlchemy
# exceptions (e.g. InvalidRequestError when the session is closed); on that
# path, reload the DagRun from the DB to avoid crashing the scheduler.
try:
events = dag_run.consumed_asset_events
set_committed_value(
dag_run,
"consumed_asset_events",
list(events) if events is not None else [],
)
except DetachedInstanceError:
except SQLAlchemyError:
log.warning(
"DagRunContext encountered DetachedInstanceError while accessing "
"consumed_asset_events; reloading DagRun from DB."
"DagRunContext failed to access consumed_asset_events; reloading DagRun from DB.",
exc_info=True,
)
from sqlalchemy import select
from sqlalchemy.orm import selectinload
Expand All @@ -137,8 +137,8 @@ def _sanitize_consumed_asset_events(cls, values: Mapping[str, Any]) -> Mapping[s
from airflow.models.dagrun import DagRun
from airflow.utils.session import create_session

# Defensive guardrail: reload DagRun with eager-loaded relationships on
# DetachedInstanceError to recover state without adding DB I/O to the hot path.
# Reload DagRun with eager-loaded relationships to recover state
# without adding DB I/O to the hot path.
with create_session() as session:
dag_run_reloaded = session.scalar(
select(DagRun)
Expand Down
6 changes: 6 additions & 0 deletions airflow-core/src/airflow/jobs/scheduler_job_runner.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this in info? Wondering if debug is enough.

Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,12 @@ def _send_dag_callbacks_to_processor(
callback: DagCallbackRequest | None = None,
) -> None:
if callback:
self.log.debug(
"Sending %s callback request for dag_id=%s, run_id=%s to DAG Processor",
"failure" if callback.is_failure_callback else "success",
callback.dag_id,
callback.run_id,
)
self.executor.send_callback(callback)
else:
self.log.debug("callback is empty")
Expand Down