### What do you see as an issue?

The documentation for zombie tasks https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html#zombie-undead-tasks is a bit abstract at the moment. There is a scope for enhancing the document by explaining how Airflow detects tasks as zombies

### Solving the problem

We can enhance the documentation by translating this query https://github.com/astronomer/airflow/blob/main/airflow/jobs/scheduler_job_runner.py#L1721 to a layman readable text in our documentation.

### Anything else

It might also help to add developer contribution steps to reproduce zombies locally.

### Are you willing to submit PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)

dag_model = session.scalars(
            with_row_locks(query, of=DagModel, session=session, **skip_locked(session=session))
        ).one_or_none()
        if not dag:
            self.log.error("Couldn't find DAG %s in DAG bag or database!", dag_run.dag_id)
            return callback
        if not dag_model:
            self.log.info(
                "DAG %s scheduling was skipped, probably because the DAG record was locked", dag_run.dag_id
            )
            return callback
        if (
            dag_run.start_date
            and dag.dagrun_timeout
            and dag_run.start_date < timezone.utcnow() - dag.dagrun_timeout
        ):
            dag_run.set_state(DagRunState.FAILED)
            unfinished_task_instances = session.scalars(
                select(TI)
                .where(TI.dag_id == dag_run.dag_id)
                .where(TI.run_id == dag_run.run_id)
                .where(TI.state.in_(State.unfinished))
            )
            for task_instance in unfinished_task_instances:
                task_instance.state = TaskInstanceState.SKIPPED
                session.merge(task_instance)
            session.flush()
            self.log.info("Run %s of %s has timed-out", dag_run.run_id, dag_run.dag_id)
            if self._should_update_dag_next_dagruns(dag, dag_model, last_dag_run=dag_run, session=session):
                dag_model.calculate_dagrun_date_fields(dag, dag.get_run_data_interval(dag_run))