**Apache Airflow version**: 2.0.0a2

**Kubernetes version (if you are using kubernetes)** (use `kubectl version`): v1.15.12

**Environment**:
- **OS** (e.g. from /etc/os-release): CentOS 7


**What happened**:

When using KubernetesExecutor, a single SIGTERM doesn't result in the scheduler actually exiting cleanly. However, it will exit after receiving a second SIGTERM.

The same behavior happens if you have an exception in the scheduler. An easy way to replicate it is to raise in `pod_mutation_hook`.

In practice, this means the scheduler doesn't get restarted by K8s after encountering a exception. Or, when terminating the scheduler pod, it sticks around until k8s ultimately sends it a SIGKILL after its grace period is up.

**What you expected to happen**:

The scheduler to exit after a single SIGTERM.

**How to reproduce it**:
The easiest way to reproduce it is to simply send a SIGKILL to your KubernetesExecutor scheduler pod:

```
$ kubectl exec {scheduler_pod_name} kill 1
```

Note, the pod stays running, while the logs report:

```
[2020-10-30 17:34:09,581] {scheduler_job.py:794} INFO - Exiting gracefully upon receiving signal 15
[2020-10-30 17:34:10,586] {process_utils.py:97} INFO - Sending Signals.SIGTERM to GPID 59
[2020-10-30 17:34:10,879] {process_utils.py:63} INFO - Process psutil.Process(pid=59, status='terminated', exitcode=0, started=
'17:33:23') (59) terminated with exit code 0
[2020-10-30 17:34:10,882] {process_utils.py:97} INFO - Sending Signals.SIGTERM to GPID 59
[2020-10-30 17:34:10,882] {scheduler_job.py:1329} INFO - Exited execute loop
```

Issue another `kill`:
```
$ kubectl exec {scheduler_pod_name} kill 1
```

And the pod will be restarted by k8s.

If you can't reproduce it, let me know and I'll try and get something running on kind.

**Anything else we need to know**:

The same behavior happens if you have an exception in the scheduler. An easy way to replicate it is to raise in a `pod_mutation_hook`.


airflow/jobs/scheduler_job.py
super().__init__()
        self.dag_ids = dag_ids
        self._log = log
    @provide_session
    def manage_slas(self, dag: DAG, session: Session = None) -> None:
        """
        Finding all tasks that have SLAs defined, and sending alert emails
        where needed. New SLA misses are also recorded in the database.
        We are assuming that the scheduler runs often, so we only check for
        tasks that should have succeeded in the past hour.
        """
        self.log.info("Running SLA Checks for %s", dag.dag_id)
        if not any(isinstance(ti.sla, timedelta) for ti in dag.tasks):
            self.log.info("Skipping SLA check for %s because no tasks in DAG have SLAs", dag)
            return
        qry = (
            session.query(TI.task_id, func.max(TI.execution_date).label('max_ti'))
            .with_hint(TI, 'USE INDEX (PRIMARY)', dialect_name='mysql')
            .filter(TI.dag_id == dag.dag_id)
            .filter(or_(TI.state == State.SUCCESS, TI.state == State.SKIPPED))
            .filter(TI.task_id.in_(dag.task_ids))
            .group_by(TI.task_id)
            .subquery('sq')
        )
        max_tis: List[TI] = (
            session.query(TI)
            .filter(
                TI.dag_id == dag.dag_id,
                TI.task_id == qry.c.task_id,
                TI.execution_date == qry.c.max_ti,