avatarManpreet Singh Minhas

Summary

This article provides a detailed guide on how to create a FastAPI/Uvicorn server Windows Service using Python.

Abstract

The article begins by introducing the concept of a Windows Service and its benefits, such as running in the background without user control and starting automatically on boot. It then moves on to explain FastAPI and Uvicorn, a web framework and ASGI web server implementation for Python, respectively. The author provides code snippets for creating a GET endpoint using FastAPI and running the Uvicorn server programmatically. The article then covers the use of PyInstaller to create executables for the server and the Windows Service, including the creation of .spec files and a bat file for building the required dist folder. The author also explains the creation of the Windows Service using win32serviceutil.ServiceFramework as the base class and provides code snippets for defining the service name, display name, and description, as well as the init method and main logic of the service. Finally, the article provides instructions for installing the Windows Service and starting the FastAPI/Uvicorn web server.

Bullet points

  • Windows Services are long-running executable applications that run in their own Windows sessions and can be set up to automatically start when the system starts or boots up.
  • FastAPI is a web framework for building APIs for Python3, built over ASIG, which allows the use of python coroutines.
  • Uvicorn is an ASIG web server implementation for Python that can be used with FastAPI to create and host web servers.
  • PyInstaller is a python package for creating executables that packs all the required files, dlls, packages, code, and python interpreter into a single install folder or file.
  • The article provides code snippets for creating a GET endpoint using FastAPI, running the Uvicorn server programmatically, and creating a Windows Service using win32serviceutil.ServiceFramework.
  • The article also provides instructions for installing the Windows Service and starting the FastAPI/Uvicorn web server.

How to Create a FastAPI / Uvicorn Server Windows Service

Photo by Inês Pimentel on Unsplash

Recently, I found myself in a position where I wanted to create a Windows service that would be responsible for starting up a FastAPI server automatically on boot up. However, I couldn’t find any article or tutorial that covers it in a structured and detailed manner. Since I got it working so wanted to share it with the community so that if anyone else wants to do the same it would be easier.

Introduction

Let us look at what a Windows Service is briefly. In a broader context, a daemon is a computer program that runs in the background without being under the control of an active user. Windows services arewhat performs the functions of a daemon on Windows OS. [1] These allow the creation of long running executable applications that run in their own Windows sessions. [2] These services can be set up to automatically start when the system starts or boots up, can be paused and restarted and do not have any user interface. It is because of all these features that Windows services are ideal in cases where one requires long running functionality which does not interfere with user activities.

There is extensive documentation for how to create a Windows service in .NET from Microsoft. However, for python the opposite is true i.e. there is no documentation available for creating Windows services. Perhaps one reason may be that people do not usually create Windows services using python. We will cover how to create a Windows service in python in the subsequent section. One thing to note is that debugging a Windows service is really challenging and there is no straightforward way to do that. Even for a .Net application service “You cannot debug or run a service application by pressing F5 or F11; you cannot immediately run a service or step into its code. Instead, you must install and start your service, and then attach a debugger to the service’s process.” [2]

FastAPI/Uvicorn

There are several tutorials available about FastAPI and Uvicorn so I won’t be going into the details about how this works. But instead, I’ll briefly go through the minimal code which we require for this application.

FastAPI is a web framework for building APIs for Python3. [3] It is built over ASIG (Asynchronous Server Gateway Interface) that allows you to make use of python coroutines (async). [4]

Uvicorn is an ASIG web server implementation for Python [5]. It can be used with FastAPI to create and host your web servers. Uvicorn is compatible with Windows. It is important to note here that for worker process management their documentation recommends usage of gunicorn etc.

Now let’s start with the code. There are only five lines for creating a GET endpoint using FastAPI. The GET method will return a dictionary/json with the status of the server. This is just a dummy endpoint, don’t read too much into this.

Next is the Uvicorn code. It is just a function that runs the Uvicorn server programmatically. We use multiple workers instead of the default 1. The server would be available at localhost:5000. We have set reload to False since reload should only be set for development purposes.

Note: The freeze_support() is required because we will be using Pyinstaller and that requires this statement so that multiprocessing works properly on Windows.

This takes care of the FastAPI/Uvicorn part of the code. You can run the server by running.

python server.py

PyInstaller

This is the most important part of getting FastAPI/Uvicorn to work with Windows Service. We will be creating an executable for the server and the windows service to make all this work together.

PyInstaller is a really good python package for creating executables. It packs all the required files, dlls, packages, code, python interpreter etc. into a single install folder or file which can be then used as a standalone executable [6]. For deployment on Windows, it is a really good option.

You can read more about PyInstaller in their documentation: https://pyinstaller.readthedocs.io/en/stable/usage.html

I have created .spec files which will handle the installer creation part.

First is the server.spec file. The only difference compared to auto generated spec file is that we need to include two hidden imports. First web_server, this is required since we pass the app as a string and to run and do not import the module explicitly. The second is encodings, this is required if you want to run this on an EC2 instance or any fresh virtual machine.

Next is the windows_service.spec file. Only two modifications in this spec file too. First is datas, we add the server build folder since we will be needing that. Second, we use a hidden import for win32timezone since it is required by the Windows Service but not imported.

This takes care of the spec files. I have created a bat file that builds the required dist folder. You need Miniconda3 or Anaconda3 installed for this to work.

Windows Service [6]

In this section, we will talk about the Windows Service itself. If you are curious about why I am using a server executable separately instead of bundling everything into a single executable, you can read about it here: Issue with using Uvicorn inside a windows service · Discussion #1410 · encode/uvicorn (github.com)

So let’s look at the Windows Service creation. We will be using win32serviceutil.ServiceFramework as the base class for our service. There are certain variables and methods that need to be implemented for the service to work.

The service name and display name and description details need to be defined at the class level.

Next, you need to define the init method.

You can read more about the CreateEvent method here:http://timgolden.me.uk/pywin32-docs/win32event__CreateEvent_meth.html

Now we move to the main logic of the service. The method called SvcDoRun would be called when the service is started.

In this method, we use Popen from subprocess module to run the server executable. The server.exe path needs to be built using sys._MEIPASS property which is set by PyInstaller. In this method, you can create a while loop that does something like checking the server status.

Finally, we need to create the SvcStop method which will be called when your service is stopped. Since we start our Uvicorn server with multiple servers it is not enough to just kill the main process. We need to handle all the child processes too. The kill_proc_tree function is for that. It takes in a pid for the parent process and then recursively kills the child processes. Then finally we terminate the main Uvicorn process. This will be a graceful shutdown to the best of my knowledge.

Installing the Windows Service

At last, we are now at a stage where we can talk about installing this newly created Windows service for the FastAPI/Uvicorn web server.

The steps for building the service and installing it are as follow:

1. Clone this repo

2. From the root repo directory run create_windows_service_installer.bat

3. Move the dist/windows_service folder to the install location. Note: Don’t move the folder after this otherwise the service won’t work.

4. Open elevated command prompt (i.e. as Admin)

5. cd to the repo root directory

6. Type install_windows_service.bat and press enter. This is a bat file which I have created for doing the installation and starting the service. This will install the service in auto start up mode. It means that whenever your PC starts the service would be started.

The windows service CLI supports various commands. I used only the startup flag to set the service to auto start. You can start, stop, remove the service and more.

Source: By the Author

The newly installed service will be available in the Services list. [To open this type Services in Windows search]

Source: By the Author

You can start and stop the service by right clicking on the service. The windows service would show up as windows_service.exe in the task manager.

Source: By the Author

You can see the Uvicorn server process as server.exe in the same list. There would be several processes for the different Uvicorn workers. It will depend on the number of logical cores available in your machine.

Source: By the Author

And the webserver would be accessible at localhost:5000. You can check the auto generated Swagger for the API at localhost:5000/docs. These are pretty awesome and you can use those to send test requests.

Source: By the Author

Conclusion

To conclude, in this article we saw how to use create a Windows Service for FastAPI/Uvicorn web server by using PyInstaller. The service is installed in auto start mode so that the webserver starts on boot. The server can be stopped using the service. The code is available here: https://github.com/msminhas93/fastapi-windows-service

I hope you found this useful. Thank you for spending the time to read my article. If you have any thoughts/suggestions please do comment. Follow for content on deep learning, machine learning, data science, computer vision and computer science. You can connect with me on LinkedIn here: https://www.linkedin.com/in/msminhas93/

References

[1] https://en.wikipedia.org/wiki/Daemon_(computing)

[2] https://docs.microsoft.com/en-us/dotnet/framework/windows-services/introduction-to-windows-service-applications

[3] https://fastapi.tiangolo.com/

[4] https://www.analyticsvidhya.com/blog/2020/11/fastapi-the-right-replacement-for-flask/

[5] https://www.uvicorn.org/

[6]https://gist.github.com/guillaumevincent/d8d94a0a44a7ec13def7f96bfb713d3f

Web Development
Programming
Python
API
Web Server
Recommended from ReadMedium