无法访问作为使用 pywin32 创建的 Windows 服务运行的 FastApi 应用程序

问题描述 投票:0回答:1

我有一个基本的fastapi

main.py
如下:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
origins = ["*"]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def read_root():
    return {"Hello": "World"}

win_service.py
如下:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import os
from threading import Thread
import uvicorn

class AppServerSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = "ABCD"
    _svc_display_name_ = "ABCD Windows Service"
    _svc_description_ = "A FastAPI application running as a Windows Service"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(
            servicemanager.EVENTLOG_INFORMATION_TYPE,
            servicemanager.PYS_SERVICE_STARTED,
            (self._svc_name_, "")
        )
        self.main()

    def main(self):
        def start_server():
            os.chdir(os.path.dirname(os.path.abspath(__file__)))
            uvicorn.run("main:app", host="0.0.0.0", port=8000)

        server_thread = Thread(target=start_server)
        server_thread.start()
        win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
        server_thread.join()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

使用 Windows 11 和 Python 版本 3.9。当我尝试使用管理cmd安装(

python win_service.py install
)并调试(
python win_service.py debug
)时,它可以工作并且我可以在http://localhost:8000

上访问它

当我启动(

python win_service.py start
)时,它就会启动,并且在Windows事件查看器中日志显示
The ABCD service has started.
,但无法通过http://localhost:8000

访问它

当它作为服务运行时,我如何访问它?

python python-3.x windows-services fastapi pywin32
1个回答
0
投票

最终创建了一个解决方法,将 fastapi 作为子进程启动:

import os
import win32serviceutil
import win32service
import win32event
import socket
import subprocess


class AppServerSvc(win32serviceutil.ServiceFramework):
    _svc_name_ = "ABCD"
    _svc_display_name_ = "ABCD Windows Service"
    _svc_description_ = "A FastAPI application running as a Windows Service"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)
        self.is_running = True
        self.process = None

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        self.main()

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        self.is_running = False
        if self.process:
            self.process.terminate()
            self.process.wait()
        win32event.SetEvent(self.hWaitStop)

    def main(self):
        uvicorn_location = r"C:\Users\username\AppData\Local\Programs\Python\Python39\Scripts\uvicorn.exe"
        command = [
            uvicorn_location,
            "main:app",
            "--host",
            "0.0.0.0",
            "--port",
            "8000"
        ]
        working_directory = r"E:\path-to-fastapi-backend"

        os.chdir(working_directory)
        self.process = subprocess.Popen(command)
        
        while self.is_running:
            rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)
            if rc == win32event.WAIT_OBJECT_0:
                break

if __name__ == "__main__":
    win32serviceutil.HandleCommandLine(AppServerSvc)
© www.soinside.com 2019 - 2024. All rights reserved.