Python: Install script as Windows Service

Начал писать на работе кодифицирующую автоматическую систему и для бота на Windows встала задача запуска в качестве службы.

Свистопляски

Начал искать в инете инфу по данной теме, но увы рабочих вариантов нашлось немного. Те, что были найдены оказались либо слишком сложными (приходилось писать кучу кода) так еще и не запускались, если например добавить парсинг конфигурационных файлов (конкретно речь о ConfigParser). Другие запускались, но к примеру не писали логи из-за того, что Application Directory устанавливался интерпретатора/враппера, а не скрипта. Даже стал задумываться о покупке программы AlwaysUP, но к счастью в архитектуре бота был выявлен изъян не учета геораспределенности сети в плане часовых поясов в связи с чем и отбросил идею приобретения этого софта. Однако вспомнил про старую утилиту srvany, что поставляется с Windows Resource Kits 2003. Потестил на Windows Server 2016 Standard и все работает как часы. И если создать в реестре необходимые ключи, то python скрипт работает вот прям на УРА (благо инфы о srvany и реестре не мало в гугле).

Usage

Собственно долго не думая накидал свой враппер для работы с srvany ибо обламывало каждый раз ручками что-то прописывать в реестре. Устанавливаем Windows Resource Kits и клонируем репозиторий на github. Убедитесь, что в %PATH% присутствует и Python и Windows Resource Kits. Сразу скажу, что придется модифицировать точку входа в программу и если вам такой метод не подходит тогда «ой». Инициализируем класс:

# параметр 1 это название службы (обычно это название файла без расширения для удобства управления утилитой net или sc)
# параметр 2 это полный путь к самому скрипту (виндовые слеши следует указывать двойными из-за особенностей экранирования символов)
# параметр 3 это название, которое будет отоброжаться в службах (в services.msc)
from pywin32service import pywin32service
myapp = pywin32service.PyWIN32Service("myapp", "d:\\myapp\\myapp.py", "MyApp")

Далее надо изменить точку входа в программу. Я использовал такую конструкцию:

if(len(sys.argv) ==2):
    if sys.argv[1] == "install":
        myapp.install()
    if sys.argv[1] == "uninstall":
        myapp.uninstall()
    if sys.argv[1] == "help":
        myapp.usage()
else:
    main()

Установка и запуск:

python myapp.py install
net start myapp
sc query myapp

Остановка и удаление службы:

net stop myapp
python myapp.py uninstall

Не сложно, понятно и работает. Для проверки работоспособности до интеграции в приложение в репозитории присутствует скрипт test.py, который при запуске будет записывать в лог текущее время с интервалом в 5 секунд.