### Overview
Some Executors, currently a subset of the local Executors, run in a single threaded fashion and have certain limitations and requirements, many of which are hardcoded. To add a new single threaded Executor would require changes to core Airflow code.
Note: This coupling often shows up with SQLite compatibility checks since it does not support multiple connections.
### Examples
- **2a**) SQLite check done in configuration.py: https://github.com/apache/airflow/blob/26f94c5370587f73ebd935cecf208c6a36bdf9b6/airflow/configuration.py#L412-L419
- **2b**) When running in standalone mode SQLite compatibility is checked: https://github.com/apache/airflow/blob/26f94c5370587f73ebd935cecf208c6a36bdf9b6/airflow/cli/commands/standalone_command.py#L160-L165
- **2c**) Sensors in `poke` mode can block execution of DAGs when running with single process Executors, currently hardcoded to DebugExecutor (although should also include SequentialExecutor): https://github.com/apache/airflow/blob/27e2101f6ee5567b2843cbccf1dca0b0e7c96186/airflow/sensors/base.py#L243
### Proposal
A static method or attribute on the Executor class which can be checked by core code.

There is a precedent already set with the `supports_ad_hoc_ti_run` attribute, see:
https://github.com/apache/airflow/blob/fb741fd87254e235f99d7d67e558dafad601f253/airflow/executors/kubernetes_executor.py#L435 https://github.com/apache/airflow/blob/26f94c5370587f73ebd935cecf208c6a36bdf9b6/airflow/www/views.py#L1735-L1737
f"since it is over MySQL's TIMESTAMP storage limit."
                    )
                raise AirflowRescheduleException(reschedule_date)
            else:
                time.sleep(self._get_next_poke_interval(started_at, run_duration, try_number))
                try_number += 1
        self.log.info("Success criteria met. Exiting.")
        return xcom_value
    def _get_next_poke_interval(
        self,
        started_at: datetime.datetime | float,
        run_duration: Callable[[], float],
        try_number: int,
    ) -> float:
        """Using the similar logic which is used for exponential backoff retry delay for operators."""
        if not self.exponential_backoff:
            return self.poke_interval
        min_backoff = int(self.poke_interval * (2 ** (try_number - 2)))
        run_hash = int(
            hashlib.sha1(f"{self.dag_id}#{self.task_id}#{started_at}#{try_number}".encode()).hexdigest(),
            16,
        )
        modded_hash = min_backoff + run_hash % min_backoff
        delay_backoff_in_seconds = min(modded_hash, timedelta.max.total_seconds() - 1)
        new_interval = min(self.timeout - int(run_duration()), delay_backoff_in_seconds)
        if self.max_wait:
            new_interval = min(self.max_wait.total_seconds(), new_interval)
        self.log.info("new %s interval is %s", self.mode, new_interval)
        return new_interval
    def prepare_for_execution(self) -> BaseOperator: