Я пытаюсь понять, почему функция автоматической перезагрузки Python Tornado не работает при настройке и запуске внутри модуля. Следующий модуль содержит класс MyTornadoApp, который настраивает и запускает автоперезагрузку, если установлена соответствующая опция:
import os
import tornado.autoreload
import tornado.web
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello from index handler!")
class MyTornadoApp:
"""Setup my custom tornado app with default settings"""
# default tornado settings
default_settings = dict(
debug=False,
autoreload=True,
compress_response=True,
port=8080,
)
default_handlers = [
(r"/", IndexHandler),
]
def __init__(self, user_settings):
self.options = {**self.default_settings, **user_settings}
if self.options['autoreload'] == True:
self._autoreload_config()
self.tornado = tornado.web.Application(self.default_handlers,
**self.options)
def _autoreload_config(self):
"""Setup autoreload for tornado"""
print("Setting up autoreload for tornado...")
# autoreload (exclusive) monitor file
monitoring_file = os.path.abspath('autoreload')
if not os.path.isfile(monitoring_file):
with open(monitoring_file, 'w', encoding='UTF-8') as f:
f.write('Do NOT delete. Monitoring changes in this file!')
tornado.autoreload.watch(monitoring_file)
tornado.autoreload.start()
Затем основной скрипт Python, приведенный ниже, создает приложение Tornado, но, к сожалению, autoreload работает только в том случае, если вызывается start (опять же, согласно предупреждающему сообщению Tornado). Любые идеи, почему это происходит? Это фича или баг? Что мне не хватает? ТИА.
import asyncio
import tornado.web
from tornadoapp import MyTornadoApp
async def main():
################################################################
# Why do I need this in order to autoreload work properly???
################################################################
if app.options['autoreload'] == True:
tornado.autoreload.start()
app.tornado.listen(app.options['port'])
print(f"Tornado is listening on port {app.options['port']}")
await asyncio.Event().wait()
if __name__ == "__main__":
my_settings = dict(
debug=False,
autoreload=True,
)
app = MyTornadoApp(my_settings)
asyncio.run(main())
Обратите внимание на предупреждающее сообщение: tornado.autoreload started more than once in the same process. Но если мы удалим строку tornado.autoreload.start() из функции main(), то автоперезагрузка не сработает, если мы изменим файл мониторинга (или любой другой отслеживаемый файл).






Это досадная причуда/недостаток asyncio.run: он молча отбрасывает любой цикл событий, который уже существовал в потоке, и создает новый для запуска основной функции. Поскольку Tornado инициализирует автоперезагрузку при построении приложения, это означает, что он использует неправильный цикл обработки событий, когда вы создаете его вне main.
Есть два возможных решения:
asyncio.get_event_loop().run_until_complete() вместо asyncio.run(). Это должно работать так, как вы ожидаете, но такое использование устарело и будет удалено в какой-то будущей версии Python.asyncio.run(), но делайте все (включая построение Приложения) внутри основной функции. Это рекомендуемая схема на будущее.