This is sample repo for setting up a Windows service from a python script. We've run into issues in the upgrade from python 3.7 to 3.10, and have found out painfully that the new asyncio default loop policy does not work when being used as a service.
Starting with python 3.8, the default loop policy has changed from SelectorEventLoop to ProactorEventLoop.
The issue is due to the ProactorEventLoop not supporting add_reader/writer. My guess is this is needed to properly support detaching from a process, because you can use the ProactorEventLoop to run the service in debug, which stays attached to the process.
After cloning this repo, install pywin32 and follow some post-installation steps.
.\venv\Scripts\activate.ps1
python -m pip install -r .\requirements.txt
As an Administrator, you must run the post-install command to place the proper DLLs into the system python.
python .\venv\Scripts\pywin32_postinstall.py -install
Copy the main.py
script into the Scripts
directory.
Copy-Item .\main.py -Destination .\venv\Scripts\
Copy the pythonservice.exe
to the Scripts
directory, next to the python script that will be run as the service.
Copy-Item .\venv\Lib\site-packages\win32\pythonservice.exe -Destination .\venv\Scripts\
Lastly, set the _exe_path_
class attribute to the pythonservice.exe
placed inside Scripts
. This is needed to
ensure the virtual environment is used for the service.
_exe_path_ = str(Path(sys.exec_prefix).joinpath('Scripts', 'pythonservice.exe'))
python .\venv\Scripts\main.py [ install | remove | start | debug ]
Looking at the pywin32 source code,
when you run a service in debug, the service is started with os.system
.
When you start the service without debug, it uses win32service.StartService()
, which in turn calls a
C function
that requires a handle to the service. With no add_reader()
method, I believe this is why it fails with the ProactorEventLoop.