How to Make Sense of Distributed Processing With Python Windows Services

Daemonize and scale your Python apps

Timothy Mugayi
Feb 5 · 5 min read
Photo by Michael on Unsplash

In part one of this article, we focused on creating daemon processes using Unix-specific packages.

In part two of this series, we dive deep into how we can do the same on a Windows machine, leveraging the equivalent Windows services.

The PyWin32 will be the core Python package that will serve as the underlying library that allows us to create Windows services that mimic Unix daemons.

The PyWin32 package is a wrapper for Windows-specific functionality and C APIs. This utility was created by Mark Hammond as an add-on that includes the Win32 API, COM support, and PythonWin extensions.

Thanks to this handy library, we have access to programmatically control Windows via the Win32 API.

Let’s jump straight into creating our first Python service that does exactly the same thing as our original daemon code was doing. We need to ensure we have installed PyWin32. To do that, run the following command:

Let’s create a base service class that extends PyWin32, win32serviceutil.ServiceFramework, so that all our child Windows services can inherit from it.

All Python Windows services will subclass the win32serviceutil.ServiceFramework class.

The PyWin32 class has a number of default methods and helper methods to make writing services in Python easier. For example, functions required to start/stop/install/remove a service; the functions typically used by a Service Control Manager (SCM).

Let’s create a custom child Windows service class that extends our base class consisting of the same logic that we saw in part one of this article, i.e., our fictitious new feed aggregator.

Test Windows Service

To ensure your Python script is working fine, first execute it inside debug mode.

Followed by executing the debug mode:

If install and debug commands work as expected, proceed and test execution of your service manually by navigating to the Windows service control panel.

Right-click on your Start button to open the Win menu. Select Run. This opens the Run box. Now type services.msc in it and hit Enter to open the Services Manager.

Search for the Windows service that you have created as depicted by the image below.

Right-click on the service OptimizationModel Winservice and click on start. This should allow the service to start executing in the background.

Python Service Not Working?

This is because everything works differently on Windows if it’s not Windows-centric.

They are a couple of issues that might happen. Something that is all too often common when working with Microsoft Windows services, such as permission issues, missing DLLs.

For those of you who develop on Windows machines, I am sure its a common everyday thing and sometimes expected before your code executes correctly. That’s if you’re running outside of Docker.

Let’s take a walk through some of the issues and possible resolutions.

1. Error: Access is denied when you try to install your Python service

To solve the above error, start your script via the command prompt by starting as administrator. Hit Windows+R to open the Run box.

Type the name of the CMD command. After typing your command, hit Ctrl+Shift+Enter to run it with admin privileges. Hitting Enter runs the command as a normal user.

execute cmd

If you’re running your code via the inbuilt terminal windows, using IDE’s such as VS Code or PyCharm, right-click → run as administrator → you should be good to go at this point.

2. Python Windows service “Error starting service: The service did not respond to the start or control request in a timely fashion”

This error can be caused by multiple issues.

Python path missing

Every process has an environment block that contains a set of environment variables and their values.

There are two types of environment variables:

  1. User environment variables (set for each user).
  2. System environment variables (set for everyone).

System Windows services run as global. Hence, your Python path should also exist within your system environment variables which takes precedence over user-defined variables in regards to the PATH environment variable.

System variables
Add Python path to system variables

Missing pywintypes

Be sure to have the file pywintypes added to C:\Program Files\Python38\Lib\site-packages\win32\pywintypes38.dll.

Please note “38” is the version of your Python installation, which depends on the version you are using.

Pywintypes can be located in C:\Program Files\Python38\Lib\site-packages\pywin32_system32\pywintypes38.dll.

Distributing Your Windows Services

Let’s modify our code so that we can have multiple instances of our news aggregate running in a distributed way. This is for illustration as our script doesn’t do much.

Spawn multiple windows Services Programmatically

Executing the above code installs three services of the same type which can be executed in parallel via your Windows services menu.

This generates the following output files with a unique PID associated with each service.

Distributed Windows services running in parallel

We can take things a step further and automate the process so that we can programmatically start and stop Windows services within our Python code as shown below.

Programmatically starting & stopping Windows services

Uninstalling Python Windows Service

Below is the command-line approach to remove a Windows service, utilizing the Windows Service Controller command-line utility SC.

Alternatively, if you wish to do it programmatically, you can invoke the function remove_service.

Sc [<ServerName>] delete [<ServiceName>].

Final Thoughts

Running background tasks leveraging on daemons and Windows services has its advantages. There is very little to configure to get your programs up and running, taking advantage of the total cores you have on your machine.

With a few lines of code, you can build out background workers that can crunch data and perform complex computations without introducing frameworks into the mix.

I hope you have found the material useful.

Better Programming

Advice for programmers.

Thanks to Zack Shapiro

Timothy Mugayi

Written by

Tech Evangelist, Instructor, Polyglot Developer with a passion for innovative technology, Father & Health Activist

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade