1

在 Windows 服务中启动 uvicorn 应用程序时,服务无法启动,并出现错误,表明信号只能在主线程中处理。

以下是事件日志中捕获的错误消息:

Traceback (most recent call last):
  File "site-packages\win32\lib\win32serviceutil.py", line 839, in SvcRun
  File "WindowsService.py", line 49, in SvcDoRun
  File "site-packages\uvicorn\main.py", line 279, in run
  File "site-packages\uvicorn\main.py", line 307, in run
  File "asyncio\base_events.py", line 584, in run_until_complete
  File "site-packages\uvicorn\main.py", line 319, in serve
  File "site-packages\uvicorn\main.py", line 459, in install_signal_handlers
  File "signal.py", line 47, in signal
ValueError: signal only works in main thread

该项目在调试模式下工作。

.\dist\WindowsService.exe debug

没有参数允许我指定不处理信号。

以下是我如何以实用的方式启动 uvicorn 应用程序:

        uvicorn.run(app.main, 
                    host=config['server']['host'], 
                    port=config['server']['port'], 
                    log_level=config['server']['loglevel'], 
                    reload=False)

该应用程序使用win32serviceutil.ServiceFramework编译为冻结的可执行文件

pyinstaller -F --hidden-import=win32timezone --additional-hooks-dir pyinstaller-hooks WindowsService.py

我希望启动 Windows 服务并运行 uvicorn 应用程序。

4

2 回答 2

1

我找到了一个解决方案,这意味着有一个由 Windows 服务调用的控制台应用程序。在我的控制台应用程序中,我有机会在主线程上工作并按要求启动 uvicorn。

子流程调用由:

 def SvcDoRun(self):
        _log('has started')

        # determine if application is a script file or frozen exe
        if getattr(sys, 'frozen', False):
            application_path = os.path.dirname(sys.executable)
        elif __file__:
            application_path = os.path.dirname(__file__)

        exe_name = os.path.join(application_path, self._app_exe_name_)
        _log('launchin subprocess for {exe_name}'.format(exe_name=exe_name))
        p = subprocess.Popen([exe_name])

        _log('is running in subprocess id {process_id}'.format(process_id=p.pid))

        while True:               
            result = win32event.WaitForSingleObject(self._stop_event, 5000)

            if result == win32event.WAIT_OBJECT_0:
                # stop requested                  
                _log('is stopping')
                p.kill()
                break

        _log('has stopped')  
于 2019-07-01T06:18:36.897 回答
0

我有同样的问题,不喜欢你运行子进程的解决方案。我发现https://github.com/encode/uvicorn/issues/526解释了这个问题。我的解决方法:

config = uvicorn.Config(app, ...)
server = uvicorn.Server(config=config)
# According to https://github.com/encode/uvicorn/issues/526, on Python 3.8+ you MIGHT also need:
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# But in my case it didn't seem to be necessary
server.install_signal_handlers = lambda: None  # this is the necessary workaround
server.run()
于 2020-09-12T17:58:08.710 回答