We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Python 3.9 compatibility issue regarding usage of threading.Thread.isAlive
<!--
Please fill this template entirely and do not erase parts of it.
We reserve the right to close without a response
bug reports which are incomplete.
-->
# Checklist
<!--
To check an item on the list replace [ ] with [x].
-->
- [x] I have verified that the issue exists against the `master` branch of Celery.
- [ ] This has already been asked to the [discussion group](https://groups.google.com/forum/#!forum/celery-users) first.
- [ ] I have read the relevant section in the
  [contribution guide](http://docs.celeryproject.org/en/latest/contributing.html#other-bugs)
  on reporting bugs.
- [x] I have checked the [issues list](https://github.com/celery/celery/issues?q=is%3Aissue+label%3A%22Issue+Type%3A+Bug+Report%22+-label%3A%22Category%3A+Documentation%22)
  for similar or identical bug reports.
- [x] I have checked the [pull requests list](https://github.com/celery/celery/pulls?q=is%3Apr+label%3A%22PR+Type%3A+Bugfix%22+-label%3A%22Category%3A+Documentation%22)
  for existing proposed fixes.
- [x] I have checked the [commit log](https://github.com/celery/celery/commits/master)
  to find out if the bug was already fixed in the master branch.
- [ ] I have included all related issues and possible duplicate issues
  in this issue (If there are none, check this box anyway).

## Mandatory Debugging Information

- [x] I have verified that the issue exists against the `master` branch of Celery.

## Optional Debugging Information

`isAlive` was deprecated and removed in Python 3.9 . Celery has the deprecation warning that will become error in Python 3.9 .

https://travis-ci.org/celery/celery/jobs/628813003#L3262-L3263

Relevant CPython PR : https://github.com/python/cpython/pull/15225


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `celery/utils/timer2.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """Scheduler for Python functions.
3 
4 .. note::
5     This is used for the thread-based worker only,
6     not for amqp/redis/sqs/qpid where :mod:`kombu.asynchronous.timer` is used.
7 """
8 from __future__ import absolute_import, print_function, unicode_literals
9 
10 import os
11 import sys
12 import threading
13 from itertools import count
14 from time import sleep
15 
16 from kombu.asynchronous.timer import Entry
17 from kombu.asynchronous.timer import Timer as Schedule
18 from kombu.asynchronous.timer import logger, to_timestamp
19 
20 from celery.five import THREAD_TIMEOUT_MAX
21 
22 TIMER_DEBUG = os.environ.get('TIMER_DEBUG')
23 
24 __all__ = ('Entry', 'Schedule', 'Timer', 'to_timestamp')
25 
26 
27 class Timer(threading.Thread):
28     """Timer thread.
29 
30     Note:
31         This is only used for transports not supporting AsyncIO.
32     """
33 
34     Entry = Entry
35     Schedule = Schedule
36 
37     running = False
38     on_tick = None
39 
40     _timer_count = count(1)
41 
42     if TIMER_DEBUG:  # pragma: no cover
43         def start(self, *args, **kwargs):
44             import traceback
45             print('- Timer starting')
46             traceback.print_stack()
47             super(Timer, self).start(*args, **kwargs)
48 
49     def __init__(self, schedule=None, on_error=None, on_tick=None,
50                  on_start=None, max_interval=None, **kwargs):
51         self.schedule = schedule or self.Schedule(on_error=on_error,
52                                                   max_interval=max_interval)
53         self.on_start = on_start
54         self.on_tick = on_tick or self.on_tick
55         threading.Thread.__init__(self)
56         self._is_shutdown = threading.Event()
57         self._is_stopped = threading.Event()
58         self.mutex = threading.Lock()
59         self.not_empty = threading.Condition(self.mutex)
60         self.daemon = True
61         self.name = 'Timer-{0}'.format(next(self._timer_count))
62 
63     def _next_entry(self):
64         with self.not_empty:
65             delay, entry = next(self.scheduler)
66             if entry is None:
67                 if delay is None:
68                     self.not_empty.wait(1.0)
69                 return delay
70         return self.schedule.apply_entry(entry)
71     __next__ = next = _next_entry  # for 2to3
72 
73     def run(self):
74         try:
75             self.running = True
76             self.scheduler = iter(self.schedule)
77 
78             while not self._is_shutdown.isSet():
79                 delay = self._next_entry()
80                 if delay:
81                     if self.on_tick:
82                         self.on_tick(delay)
83                     if sleep is None:  # pragma: no cover
84                         break
85                     sleep(delay)
86             try:
87                 self._is_stopped.set()
88             except TypeError:  # pragma: no cover
89                 # we lost the race at interpreter shutdown,
90                 # so gc collected built-in modules.
91                 pass
92         except Exception as exc:
93             logger.error('Thread Timer crashed: %r', exc, exc_info=True)
94             sys.stderr.flush()
95             os._exit(1)
96 
97     def stop(self):
98         self._is_shutdown.set()
99         if self.running:
100             self._is_stopped.wait()
101             self.join(THREAD_TIMEOUT_MAX)
102             self.running = False
103 
104     def ensure_started(self):
105         if not self.running and not self.isAlive():
106             if self.on_start:
107                 self.on_start(self)
108             self.start()
109 
110     def _do_enter(self, meth, *args, **kwargs):
111         self.ensure_started()
112         with self.mutex:
113             entry = getattr(self.schedule, meth)(*args, **kwargs)
114             self.not_empty.notify()
115             return entry
116 
117     def enter(self, entry, eta, priority=None):
118         return self._do_enter('enter_at', entry, eta, priority=priority)
119 
120     def call_at(self, *args, **kwargs):
121         return self._do_enter('call_at', *args, **kwargs)
122 
123     def enter_after(self, *args, **kwargs):
124         return self._do_enter('enter_after', *args, **kwargs)
125 
126     def call_after(self, *args, **kwargs):
127         return self._do_enter('call_after', *args, **kwargs)
128 
129     def call_repeatedly(self, *args, **kwargs):
130         return self._do_enter('call_repeatedly', *args, **kwargs)
131 
132     def exit_after(self, secs, priority=10):
133         self.call_after(secs, sys.exit, priority)
134 
135     def cancel(self, tref):
136         tref.cancel()
137 
138     def clear(self):
139         self.schedule.clear()
140 
141     def empty(self):
142         return not len(self)
143 
144     def __len__(self):
145         return len(self.schedule)
146 
147     def __bool__(self):
148         """``bool(timer)``."""
149         return True
150     __nonzero__ = __bool__
151 
152     @property
153     def queue(self):
154         return self.schedule.queue
155
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/celery/utils/timer2.py b/celery/utils/timer2.py
--- a/celery/utils/timer2.py
+++ b/celery/utils/timer2.py
@@ -102,7 +102,7 @@
             self.running = False
 
     def ensure_started(self):
-        if not self.running and not self.isAlive():
+        if not self.running and not self.is_alive():
             if self.on_start:
                 self.on_start(self)
             self.start()

{"golden_diff": "diff --git a/celery/utils/timer2.py b/celery/utils/timer2.py\n--- a/celery/utils/timer2.py\n+++ b/celery/utils/timer2.py\n@@ -102,7 +102,7 @@\n             self.running = False\n \n     def ensure_started(self):\n-        if not self.running and not self.isAlive():\n+        if not self.running and not self.is_alive():\n             if self.on_start:\n                 self.on_start(self)\n             self.start()\n", "issue": "Python 3.9 compatibility issue regarding usage of threading.Thread.isAlive\n<!--\r\nPlease fill this template entirely and do not erase parts of it.\r\nWe reserve the right to close without a response\r\nbug reports which are incomplete.\r\n-->\r\n# Checklist\r\n<!--\r\nTo check an item on the list replace [ ] with [x].\r\n-->\r\n- [x] I have verified that the issue exists against the `master` branch of Celery.\r\n- [ ] This has already been asked to the [discussion group](https://groups.google.com/forum/#!forum/celery-users) first.\r\n- [ ] I have read the relevant section in the\r\n  [contribution guide](http://docs.celeryproject.org/en/latest/contributing.html#other-bugs)\r\n  on reporting bugs.\r\n- [x] I have checked the [issues list](https://github.com/celery/celery/issues?q=is%3Aissue+label%3A%22Issue+Type%3A+Bug+Report%22+-label%3A%22Category%3A+Documentation%22)\r\n  for similar or identical bug reports.\r\n- [x] I have checked the [pull requests list](https://github.com/celery/celery/pulls?q=is%3Apr+label%3A%22PR+Type%3A+Bugfix%22+-label%3A%22Category%3A+Documentation%22)\r\n  for existing proposed fixes.\r\n- [x] I have checked the [commit log](https://github.com/celery/celery/commits/master)\r\n  to find out if the bug was already fixed in the master branch.\r\n- [ ] I have included all related issues and possible duplicate issues\r\n  in this issue (If there are none, check this box anyway).\r\n\r\n## Mandatory Debugging Information\r\n\r\n- [x] I have verified that the issue exists against the `master` branch of Celery.\r\n\r\n## Optional Debugging Information\r\n\r\n`isAlive` was deprecated and removed in Python 3.9 . Celery has the deprecation warning that will become error in Python 3.9 .\r\n\r\nhttps://travis-ci.org/celery/celery/jobs/628813003#L3262-L3263\r\n\r\nRelevant CPython PR : https://github.com/python/cpython/pull/15225\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Scheduler for Python functions.\n\n.. note::\n    This is used for the thread-based worker only,\n    not for amqp/redis/sqs/qpid where :mod:`kombu.asynchronous.timer` is used.\n\"\"\"\nfrom __future__ import absolute_import, print_function, unicode_literals\n\nimport os\nimport sys\nimport threading\nfrom itertools import count\nfrom time import sleep\n\nfrom kombu.asynchronous.timer import Entry\nfrom kombu.asynchronous.timer import Timer as Schedule\nfrom kombu.asynchronous.timer import logger, to_timestamp\n\nfrom celery.five import THREAD_TIMEOUT_MAX\n\nTIMER_DEBUG = os.environ.get('TIMER_DEBUG')\n\n__all__ = ('Entry', 'Schedule', 'Timer', 'to_timestamp')\n\n\nclass Timer(threading.Thread):\n    \"\"\"Timer thread.\n\n    Note:\n        This is only used for transports not supporting AsyncIO.\n    \"\"\"\n\n    Entry = Entry\n    Schedule = Schedule\n\n    running = False\n    on_tick = None\n\n    _timer_count = count(1)\n\n    if TIMER_DEBUG:  # pragma: no cover\n        def start(self, *args, **kwargs):\n            import traceback\n            print('- Timer starting')\n            traceback.print_stack()\n            super(Timer, self).start(*args, **kwargs)\n\n    def __init__(self, schedule=None, on_error=None, on_tick=None,\n                 on_start=None, max_interval=None, **kwargs):\n        self.schedule = schedule or self.Schedule(on_error=on_error,\n                                                  max_interval=max_interval)\n        self.on_start = on_start\n        self.on_tick = on_tick or self.on_tick\n        threading.Thread.__init__(self)\n        self._is_shutdown = threading.Event()\n        self._is_stopped = threading.Event()\n        self.mutex = threading.Lock()\n        self.not_empty = threading.Condition(self.mutex)\n        self.daemon = True\n        self.name = 'Timer-{0}'.format(next(self._timer_count))\n\n    def _next_entry(self):\n        with self.not_empty:\n            delay, entry = next(self.scheduler)\n            if entry is None:\n                if delay is None:\n                    self.not_empty.wait(1.0)\n                return delay\n        return self.schedule.apply_entry(entry)\n    __next__ = next = _next_entry  # for 2to3\n\n    def run(self):\n        try:\n            self.running = True\n            self.scheduler = iter(self.schedule)\n\n            while not self._is_shutdown.isSet():\n                delay = self._next_entry()\n                if delay:\n                    if self.on_tick:\n                        self.on_tick(delay)\n                    if sleep is None:  # pragma: no cover\n                        break\n                    sleep(delay)\n            try:\n                self._is_stopped.set()\n            except TypeError:  # pragma: no cover\n                # we lost the race at interpreter shutdown,\n                # so gc collected built-in modules.\n                pass\n        except Exception as exc:\n            logger.error('Thread Timer crashed: %r', exc, exc_info=True)\n            sys.stderr.flush()\n            os._exit(1)\n\n    def stop(self):\n        self._is_shutdown.set()\n        if self.running:\n            self._is_stopped.wait()\n            self.join(THREAD_TIMEOUT_MAX)\n            self.running = False\n\n    def ensure_started(self):\n        if not self.running and not self.isAlive():\n            if self.on_start:\n                self.on_start(self)\n            self.start()\n\n    def _do_enter(self, meth, *args, **kwargs):\n        self.ensure_started()\n        with self.mutex:\n            entry = getattr(self.schedule, meth)(*args, **kwargs)\n            self.not_empty.notify()\n            return entry\n\n    def enter(self, entry, eta, priority=None):\n        return self._do_enter('enter_at', entry, eta, priority=priority)\n\n    def call_at(self, *args, **kwargs):\n        return self._do_enter('call_at', *args, **kwargs)\n\n    def enter_after(self, *args, **kwargs):\n        return self._do_enter('enter_after', *args, **kwargs)\n\n    def call_after(self, *args, **kwargs):\n        return self._do_enter('call_after', *args, **kwargs)\n\n    def call_repeatedly(self, *args, **kwargs):\n        return self._do_enter('call_repeatedly', *args, **kwargs)\n\n    def exit_after(self, secs, priority=10):\n        self.call_after(secs, sys.exit, priority)\n\n    def cancel(self, tref):\n        tref.cancel()\n\n    def clear(self):\n        self.schedule.clear()\n\n    def empty(self):\n        return not len(self)\n\n    def __len__(self):\n        return len(self.schedule)\n\n    def __bool__(self):\n        \"\"\"``bool(timer)``.\"\"\"\n        return True\n    __nonzero__ = __bool__\n\n    @property\n    def queue(self):\n        return self.schedule.queue\n", "path": "celery/utils/timer2.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"Scheduler for Python functions.\n\n.. note::\n    This is used for the thread-based worker only,\n    not for amqp/redis/sqs/qpid where :mod:`kombu.asynchronous.timer` is used.\n\"\"\"\nfrom __future__ import absolute_import, print_function, unicode_literals\n\nimport os\nimport sys\nimport threading\nfrom itertools import count\nfrom time import sleep\n\nfrom kombu.asynchronous.timer import Entry\nfrom kombu.asynchronous.timer import Timer as Schedule\nfrom kombu.asynchronous.timer import logger, to_timestamp\n\nfrom celery.five import THREAD_TIMEOUT_MAX\n\nTIMER_DEBUG = os.environ.get('TIMER_DEBUG')\n\n__all__ = ('Entry', 'Schedule', 'Timer', 'to_timestamp')\n\n\nclass Timer(threading.Thread):\n    \"\"\"Timer thread.\n\n    Note:\n        This is only used for transports not supporting AsyncIO.\n    \"\"\"\n\n    Entry = Entry\n    Schedule = Schedule\n\n    running = False\n    on_tick = None\n\n    _timer_count = count(1)\n\n    if TIMER_DEBUG:  # pragma: no cover\n        def start(self, *args, **kwargs):\n            import traceback\n            print('- Timer starting')\n            traceback.print_stack()\n            super(Timer, self).start(*args, **kwargs)\n\n    def __init__(self, schedule=None, on_error=None, on_tick=None,\n                 on_start=None, max_interval=None, **kwargs):\n        self.schedule = schedule or self.Schedule(on_error=on_error,\n                                                  max_interval=max_interval)\n        self.on_start = on_start\n        self.on_tick = on_tick or self.on_tick\n        threading.Thread.__init__(self)\n        self._is_shutdown = threading.Event()\n        self._is_stopped = threading.Event()\n        self.mutex = threading.Lock()\n        self.not_empty = threading.Condition(self.mutex)\n        self.daemon = True\n        self.name = 'Timer-{0}'.format(next(self._timer_count))\n\n    def _next_entry(self):\n        with self.not_empty:\n            delay, entry = next(self.scheduler)\n            if entry is None:\n                if delay is None:\n                    self.not_empty.wait(1.0)\n                return delay\n        return self.schedule.apply_entry(entry)\n    __next__ = next = _next_entry  # for 2to3\n\n    def run(self):\n        try:\n            self.running = True\n            self.scheduler = iter(self.schedule)\n\n            while not self._is_shutdown.isSet():\n                delay = self._next_entry()\n                if delay:\n                    if self.on_tick:\n                        self.on_tick(delay)\n                    if sleep is None:  # pragma: no cover\n                        break\n                    sleep(delay)\n            try:\n                self._is_stopped.set()\n            except TypeError:  # pragma: no cover\n                # we lost the race at interpreter shutdown,\n                # so gc collected built-in modules.\n                pass\n        except Exception as exc:\n            logger.error('Thread Timer crashed: %r', exc, exc_info=True)\n            sys.stderr.flush()\n            os._exit(1)\n\n    def stop(self):\n        self._is_shutdown.set()\n        if self.running:\n            self._is_stopped.wait()\n            self.join(THREAD_TIMEOUT_MAX)\n            self.running = False\n\n    def ensure_started(self):\n        if not self.running and not self.is_alive():\n            if self.on_start:\n                self.on_start(self)\n            self.start()\n\n    def _do_enter(self, meth, *args, **kwargs):\n        self.ensure_started()\n        with self.mutex:\n            entry = getattr(self.schedule, meth)(*args, **kwargs)\n            self.not_empty.notify()\n            return entry\n\n    def enter(self, entry, eta, priority=None):\n        return self._do_enter('enter_at', entry, eta, priority=priority)\n\n    def call_at(self, *args, **kwargs):\n        return self._do_enter('call_at', *args, **kwargs)\n\n    def enter_after(self, *args, **kwargs):\n        return self._do_enter('enter_after', *args, **kwargs)\n\n    def call_after(self, *args, **kwargs):\n        return self._do_enter('call_after', *args, **kwargs)\n\n    def call_repeatedly(self, *args, **kwargs):\n        return self._do_enter('call_repeatedly', *args, **kwargs)\n\n    def exit_after(self, secs, priority=10):\n        self.call_after(secs, sys.exit, priority)\n\n    def cancel(self, tref):\n        tref.cancel()\n\n    def clear(self):\n        self.schedule.clear()\n\n    def empty(self):\n        return not len(self)\n\n    def __len__(self):\n        return len(self.schedule)\n\n    def __bool__(self):\n        \"\"\"``bool(timer)``.\"\"\"\n        return True\n    __nonzero__ = __bool__\n\n    @property\n    def queue(self):\n        return self.schedule.queue\n", "path": "celery/utils/timer2.py"}]}