Im pretty new to programming and Python and i have crated an API using FastAPI that i need to run on Windows, i want to run it as a service. The server will start and run fine, but when i try to stop it Windows throws an error and i think its because im not "stopping" uvicorn and i cant figure out how to. I've been googling and tried to run Uvicorn in a Daemon thread because i read that daemon threads will shutdown when the main thread exits, but that did not help either. Im converting the app to exe using cx_Freeze. Could anyone point me in the right direction?
Im using this Template for cx_Freeze: https://github.com/marcelotduarte/cx_Freeze/tree/main/cx_Freeze/samples/service
Im on Windows 10, Python 3.9.1, Uvicorn 0.13.3, cx_Freeze 6.5
ServiceHandler.py
import os
import sys
import cx_Logging
import api
import logging
import threading
from uvicorn import Config, Server
logging.basicConfig(
filename = os.path.join(os.path.dirname(sys.executable), "log.txt"),
level = logging.DEBUG,
format = '[API] %(levelname)-7.7s %(message)s'
)
class Handler:
# no parameters are permitted; all configuration should be placed in the
# configuration file and handled in the initialize() method
def __init__(self):
self.stopEvent = threading.Event()
self.stopRequestedEvent = threading.Event()
# called when the service is starting
def initialize(self, configFileName):
self.directory = os.path.dirname(sys.executable)
cx_Logging.StartLogging(os.path.join(self.directory, "testing.log"), cx_Logging.DEBUG)
#pass
# called when the service is starting immediately after initialize()
# use this to perform the work of the service; don't forget to set or check
# for the stop event or the service GUI will not respond to requests to
# stop the service
def run(self):
cx_Logging.Debug("stdout=%r", sys.stdout)
sys.stdout = open(os.path.join(self.directory, "stdout.log"), "a")
sys.stderr = open(os.path.join(self.directory, "stderr.log"), "a")
self.main()
self.stopRequestedEvent.wait()
self.stopEvent.set()
# called when the service is being stopped by the service manager GUI
def stop(self):
try:
logging.debug("Stopping Service")
self.stopRequestedEvent.set()
self.stopEvent.wait()
# How to stop the server???
except Exception as e:
logging.error(e)
def main(self):
try:
self.config = Config(app=api.app, host="0.0.0.0", port=8004, reload=False)
self.app_server = Server(self.config)
self.app_server.install_signal_handlers = lambda: None # Need this line, or the server wont start
self.app_server.run()
except Exception as e:
logging.error(e)
setup.py
from cx_Freeze import setup, Executable
options = {
"build_exe": {
"packages": ["uvicorn", "fastapi", "pydantic", "threading"],
"includes": ["ServiceHandler", "cx_Logging", "ipaddress", "colorsys"],
"excludes": ["tkinter"],
}
}
executables = [
Executable(
"Config.py",
base="Win32Service",
target_name="api.exe",
)
]
setup(
name="TestService",
version="0.1",
description="Sample Windows serice",
executables=executables,
options=options,
)
I've also read this; https://github.com/encode/uvicorn/issues/742 But my knowledge is limited, so i dont quite understand how to implement it in my app?