Как запустить сценарий Python в качестве службы в Windows?


272

Я делаю набросок архитектуры набора программ, которые совместно используют различные взаимосвязанные объекты, хранящиеся в базе данных. Я хочу, чтобы одна из программ действовала как служба, обеспечивающая интерфейс более высокого уровня для операций с этими объектами, а другие программы - для доступа к объектам через эту службу.

В настоящее время я стремлюсь к Python и фреймворку Django в качестве технологий для реализации этой службы. Я почти уверен, что понимаю, как демонизировать программу Python в Linux. Однако это необязательный элемент спецификации, что система должна поддерживать Windows. У меня мало опыта программирования для Windows и вообще нет опыта работы со службами Windows.

Можно ли запускать программы Python как службу Windows (т.е. запускать ее автоматически без входа пользователя в систему)? Мне не обязательно реализовывать эту часть, но мне нужно общее представление о том, как это будет сделано, чтобы решить, следует ли проектировать в соответствии с этими направлениями.

Изменить: Спасибо за все ответы, они довольно исчерпывающие. Я хотел бы узнать еще кое-что: как Windows узнает о моей службе? Могу ли я управлять этим с помощью родных утилит Windows? Что эквивалентно помещению сценария запуска / остановки в /etc/init.d?

Ответы:


260

Да, ты можешь. Я делаю это с помощью библиотек pythoncom, которые входят в состав ActivePython или могут быть установлены с pywin32 (расширения Python для Windows).

Это базовый скелет для простого сервиса:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

Ваш код войдет в main()метод - обычно с каким-то бесконечным циклом, который может быть прерван проверкой флага, установленного вами в SvcStopметоде


24
После кодирования как мне сказать Windows запустить это как службу?
Kit

34
@Kit: запустите ваш скрипт из командной строки с параметром "install". Тогда вы сможете увидеть свое приложение в списке служб Windows, где вы можете запустить его, остановить или настроить автоматический запуск
Рикардо Рейес,

17
Вы особо упоминаете pythoncom и импортируете его в свой пример кода. Проблема в том, что вы никогда не используете pythoncom где-либо в своем примере кода, вы только импортируете его. Зачем уделять ему особое внимание, а затем не показывать его использование?
Buttons840

11
Почему за socket.setdefaulttimeout(60)это? Нужен ли он для службы или просто случайно скопирован из существующей службы? :)
Тимур

7
chrisumbel.com/article/windows_services_in_python Это похожий пример, но более полный
csprabala

43

Хотя пару недель назад я поддержал выбранный ответ, тем временем я еще больше боролся с этой темой. Похоже, что иметь специальную установку Python и использовать специальные модули для запуска скрипта как службы - это просто неправильный путь. Что насчет портативности и тому подобного?

Я наткнулся на замечательный Non-sucking Service Manager , который сделал работу со службами Windows действительно простой и разумной. Я подумал, что, поскольку я могу передавать параметры установленной службе, я могу с таким же успехом выбрать исполняемый файл Python и передать свой скрипт в качестве опции.

Я еще не пробовал это решение, но сделаю это прямо сейчас и буду обновлять этот пост в процессе. Я также заинтересован в использовании virtualenvs в Windows, поэтому рано или поздно я могу придумать учебник и дать ссылку на него здесь.


При удаче? Я создаю очень простой сайт для клиента, и мне не нужно использовать весь стек Apache. Кроме того, самостоятельное создание сервиса звучало как приглашение к неприятностям, как я читал из других комментариев.
Джаран

Да, это работает, и это очень легко сделать. Вы просто указываете путь и аргументы для сценария. Мне удалось заставить мою работать без консоли на тот случай, если у кого-то каким-то образом окажется окно консоли.
kmcguire

Хотя это, по-видимому, работает, существуют и другие трудности, особенно когда вам «не нужно использовать весь стек Apache»: например, Gunicorn еще не работает в Windows, что на самом деле было для меня остановкой.
mknaf

4
Уловка здесь заключается в том, чтобы запустить python.exe как службу и ваш скрипт python в качестве параметра: например, «nssm install MyServiceName c: \ python27 \ python.exe c: \ temp \ myscript.py»
poleguy

Работает отлично! В системе с несколькими виртуальными средами путь может ссылаться на исполняемый файл интерпретатора Python в каталоге Scripts желаемой виртуальной среды. Похоже, что new-serviceв PowerShell это должно быть возможно, но запуск (и мониторинг) скрипта как службы, очевидно, требует гораздо большего количества деталей, о которых nssm очень хорошо заботится.
Фред Шлейфер

33

Самый простой способ - использовать: NSSM - Non-Sucking Service Manager. Просто скачайте и разархивируйте в любое место по вашему выбору. Это автономная утилита, около 300 КБ (намного меньше, чем установка всего пакета pywin32 только для этой цели), и никакой «установки» не требуется. Архив содержит 64-битную и 32-битную версии утилиты. Любой из них должен хорошо работать в текущих системах (вы можете использовать 32-битную версию для управления службами в 64-битных системах).

GUI подход

1 - установить программу python как службу. Откройте приглашение Win от имени администратора

c:\>nssm.exe install WinService

2 - На консоли GUI NSSM:

путь: C: \ Python27 \ Python27.exe

Каталог запуска: C: \ Python27

Аргументы: c: \ WinService.py

3 - проверьте созданные сервисы на services.msc

Подход к написанию сценариев (без графического интерфейса)

Это удобно, если ваша служба должна быть частью автоматизированной, неинтерактивной процедуры, которая может находиться вне вашего контроля, например, пакетного сценария или сценария установки. Предполагается, что команды выполняются с правами администратора.

Для удобства команды описаны здесь, просто указав утилиту как nssm.exe. Тем не менее, рекомендуется более явно ссылаться на него в сценариях с полным путем c:\path\to\nssm.exe, поскольку это автономный исполняемый файл, который может находиться на частном пути, о котором система не знает.

1. Установите службу

Вы должны указать имя службы, путь к соответствующему исполняемому файлу Python и путь к скрипту:

nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"

Более подробно:

nssm.exe install ProjectService 
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"

В качестве альтернативы вы можете захотеть, чтобы ваше приложение Python запускалось как модуль Python. Один из простых подходов - сообщить nssm, что ему необходимо перейти в правильный стартовый каталог, как вы сделали бы сами при запуске из командной оболочки:

nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"

Этот подход хорошо работает с виртуальными средами и автономными (встроенными) установками Python. Просто убедитесь, что вы правильно решили все проблемы с путями в этих средах с помощью обычных методов. nssm может при необходимости устанавливать переменные среды (например, PYTHONPATH), а также запускать пакетные сценарии.

2. Для запуска службы

nssm.exe start ProjectService 

3. Чтобы остановить службу

nssm.exe stop ProjectService

4. Чтобы удалить службу , укажите confirmпараметр, чтобы пропустить интерактивное подтверждение.

nssm.exe remove ProjectService confirm

Раньше я использовал nssm.exe для установки моего Visual Studio C ++ .exe в качестве службы, а теперь я могу использовать nssm.exe для своего Python .pyc в качестве службы. Спасибо.
etoricky

Примечание: если ваш * .py скрипт находится в папке с пробелом (например: C: \ Program Files \ myapp.py), необходимо указать аргументы в кавычках: Аргументы: «C: \ Program Files \ myapp.py»
Юрий Козлов

Как создать виртуальную среду?
Shaik Moeed

Не теряйте больше времени и используйте подход NSSM. Для виртуальной среды вам нужно только указать исполняемый файл python внутри папки virtualenv.
Густаво Гонсалвеш

23

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

Способ 1. Используйте instsrv и srvany из rktools.exe

Для Windows Home Server или Windows Server 2003 (также работает с WinXP) Windows Server 2003 Resource Kit Tools поставляется с утилитами, которые можно использовать в тандеме для этого, под названием instsrv.exe и srvany.exe . См. Эту статью базы знаний Майкрософт KB137890 для получения подробной информации о том, как использовать эти утилиты.

Для Windows Home Server есть отличная удобная оболочка для этих утилит под названием « Any Service Installer ».

Метод 2: используйте ServiceInstaller для Windows NT

Существует еще одна альтернатива с использованием ServiceInstaller для Windows NT (которую можно загрузить здесь ) с доступными инструкциями на языке Python . Вопреки названию, он работает как с Windows 2000, так и с Windows XP. Вот несколько инструкций по установке скрипта Python в качестве службы.

Установка скрипта Python

Запустите ServiceInstaller, чтобы создать новую службу. (В этом примере предполагается, что python установлен в c: \ python25)

Service Name  : PythonTest
Display Name : PythonTest 
Startup : Manual (or whatever you like)
Dependencies : (Leave blank or fill to fit your needs)
Executable : c:\python25\python.exe
Arguments : c:\path_to_your_python_script\test.py
Working Directory : c:\path_to_your_python_script

После установки откройте приложение «Службы» панели управления, выберите и запустите службу PythonTest.

После своего первоначального ответа я заметил, что на SO уже были опубликованы тесно связанные вопросы и ответы. Смотрите также:

Могу ли я запустить сценарий Python как службу (в Windows)? Как?

Как мне сообщить Windows о службе, которую я написал на Python?


Я только что заметил, что уже есть другие похожие вопросы и ответы: stackoverflow.com/questions/32404/… stackoverflow.com/questions/34328/…
popcnt

Установщик служб не работает с 64-битной архитектурой, поэтому вариант 1 становится вариантом перехода.
Ной Кэмпбелл

Приведенная выше ссылка на ServiceInstaller больше не работает. Я нашел его здесь: sites.google.com/site/conort/…
LarsH

2
вне примечания, я не думаю, NTчто это обязательно "противоречит" названию, по крайней мере, не в языке программистов. Это просто относится к « архитектуре NT », а не к « марке NT ». Тем не менее, согласно сообщениям в Википедии, этот вопрос подлежит обсуждению, поскольку «это не официальный термин Microsoft», но, тем не менее, существует традиция такого мышления.
n611x007 09

23

Самый простой способ добиться этого - использовать встроенную команду sc.exe:

sc create PythonApp binPath= "C:\Python34\Python.exe --C:\tmp\pythonscript.py"

Ссылки:

  1. https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
  2. При создании службы с помощью sc.exe, как передать параметры контекста?

Думаю, проблема в самой вашей команде или приложении. В любом случае, проверьте этот support.microsoft.com/en-us/help/886695/…
pyOwner

Мое приложение отлично работает вне службы, и я безрезультатно использовал тот же код, что и выше.
nimeresam

Как создать виртуальную среду?
Shaik Moeed

Вы пробовали virtualenv?
pyOwner 05

3
Это не работает. Служба Windows должна предоставлять определенный интерфейс, который делает пакет pywin32. Однако простого старого скрипта Python будет недостаточно.
Сиддхартха Ганди,

17

Пошаговое объяснение, как заставить его работать:

1- Сначала создайте файл python в соответствии с основным скелетом, упомянутым выше. И сохраните его по пути, например: "c: \ PythonFiles \ AppServerSvc.py"

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"


    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_,''))
        self.main()

    def main(self):
        # Your business logic or call to any class should be here
        # this time it creates a text.txt and writes Test Service in a daily manner 
        f = open('C:\\test.txt', 'a')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            f.write('Test Service  \n')
            f.flush()
            # block for 24*60*60 seconds and wait for a stop event
            # it is used for a one-day loop
            rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
        f.write('shut down \n')
        f.close()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

2 - На этом шаге мы должны зарегистрировать нашу службу.

Запустите командную строку от имени администратора и введите:

sc create TestService binpath = "C: \ Python36 \ Python.exe c: \ PythonFiles \ AppServerSvc.py" DisplayName = "TestService" start = auto

первый аргумент binpath - это путь к python.exe

второй аргумент binpath - это путь к вашему файлу python, который мы уже создали

Не упустите возможность ставить один пробел после каждого знака " = ".

Тогда, если все в порядке, вы должны увидеть

[SC] CreateService УСПЕХ

Теперь ваша служба Python установлена ​​как служба Windows. Вы можете увидеть это в Service Manager и в реестре в разделе:

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ TestService

3- Хорошо. Вы можете запустить свою службу в диспетчере служб.

Вы можете выполнить любой файл python, который предоставляет этот скелет службы.


Есть много плохих примеров того, как использовать SetEvent(self.hWaitStop)и WaitForSingleObject. Основываясь на бездумном копировании здесь, наверное, выбранного ответа. Это хороший способ сделать это, который работает как для аргументов «отладка», так и для аргументов «стоп». (Часть об использовании SC кажется излишней, когда HandleCommandLineвыполняется задание и может запускаться отладка.)
Alias_Knagg

5

pysc: диспетчер управления службами на Python

Пример сценария для запуска как службы, взятый с pythonhosted.org :

from xmlrpc.server import SimpleXMLRPCServer

from pysc import event_stop


class TestServer:

    def echo(self, msg):
        return msg


if __name__ == '__main__':
    server = SimpleXMLRPCServer(('127.0.0.1', 9001))

    @event_stop
    def stop():
        server.server_close()

    server.register_instance(TestServer())
    server.serve_forever()

Создать и запустить сервис

import os
import sys
from xmlrpc.client import ServerProxy

import pysc


if __name__ == '__main__':
    service_name = 'test_xmlrpc_server'
    script_path = os.path.join(
        os.path.dirname(__file__), 'xmlrpc_server.py'
    )
    pysc.create(
        service_name=service_name,
        cmd=[sys.executable, script_path]
    )
    pysc.start(service_name)

    client = ServerProxy('http://127.0.0.1:9001')
    print(client.echo('test scm'))

Остановить и удалить службу

import pysc

service_name = 'test_xmlrpc_server'

pysc.stop(service_name)
pysc.delete(service_name)
pip install pysc

3
Кто-нибудь знает, почему за это проголосовали против? Похоже, хорошее решение.
Джаррод Чесни

4

nssm в Python 3+

(Я преобразовал свой файл .py в .exe с помощью pyinstaller )

nssm: как было сказано ранее

  • запустите nssm install {ServiceName}
  • На консоли NSSM:

    путь: путь \ к \ вашей \ программе.exe

    Каталог запуска: путь \ to \ your \ # такой же, как путь, но без вашего program.exe

    Аргументы: пусто

Если вы не хотите конвертировать свой проект в .exe

  • создать файл .bat с python {{your python.py file name}}
  • и установите путь к файлу .bat

Как создать виртуальную среду?
Shaik Moeed

3

Я начал хостинг как услугу с pywin32 .

Все было хорошо, но я столкнулся с проблемой, что служба не могла запуститься в течение 30 секунд (тайм-аут по умолчанию для Windows) при запуске системы. Для меня это было критично, потому что запуск Windows происходил одновременно на нескольких виртуальных машинах, размещенных на одной физической машине, и нагрузка ввода-вывода была огромной. Сообщения об ошибках были:

Error 1053: The service did not respond to the start or control request in a timely fashion.

Error 7009: Timeout (30000 milliseconds) waiting for the <ServiceName> service to connect.

Я много боролся с pywin, но в итоге использовал NSSM, как было предложено в этом ответе . На него было очень легко перейти.


1

Полный пример pywin32 с использованием цикла или подпотока

Поработав над этим в течение нескольких дней, вот ответ, который я хотел бы найти, используя pywin32, чтобы он оставался красивым и самодостаточным.

Это полный рабочий код для решения на основе одного цикла и одного потока. Он может работать как на python 2, так и на 3, хотя я тестировал только последнюю версию на 2.7 и Win7. Цикл должен подходить для кода опроса, а протектор должен работать с кодом, более похожим на сервер. Кажется, он прекрасно работает с wsgi-сервером официантки , у которого нет стандартного способа корректного завершения работы.

Я также хотел бы отметить, что, похоже, существует множество примеров, подобных этому , которые почти полезны, но на самом деле вводят в заблуждение, потому что они слепо вырезали и вставляли другие примеры. Я могу ошибаться. но зачем создавать событие, если вы его никогда не ждете?

Тем не менее, я все еще чувствую, что я здесь несколько шатко, особенно в отношении того, насколько чистым является выход из версии потока, но, по крайней мере, я считаю, что здесь нет ничего вводящего в заблуждение .

Для запуска просто скопируйте код в файл и следуйте инструкциям.

Обновить:

Используйте простой флаг для завершения потока. Важным моментом является то, что печать «нить сделана».
Более подробный пример выхода из потока неконтролируемого сервера см. В моем сообщении о wsgi-сервере официантки .

# uncomment mainthread() or mainloop() call below
# run without parameters to see HandleCommandLine options
# install service with "install" and remove with "remove"
# run with "debug" to see print statements
# with "start" and "stop" watch for files to appear
# check Windows EventViever for log messages

import socket
import sys
import threading
import time
from random import randint
from os import path

import servicemanager
import win32event
import win32service
import win32serviceutil
# see http://timgolden.me.uk/pywin32-docs/contents.html for details


def dummytask_once(msg='once'):
    fn = path.join(path.dirname(__file__),
                '%s_%s.txt' % (msg, randint(1, 10000)))
    with open(fn, 'w') as fh:
        print(fn)
        fh.write('')


def dummytask_loop():
    global do_run
    while do_run:
        dummytask_once(msg='loop')
        time.sleep(3)


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global do_run
        do_run = True
        print('thread start\n')
        dummytask_loop()
        print('thread done\n')

    def exit(self):
        global do_run
        do_run = False


class SMWinservice(win32serviceutil.ServiceFramework):
    _svc_name_ = 'PyWinSvc'
    _svc_display_name_ = 'Python Windows Service'
    _svc_description_ = 'An example of a windows service in Python'

    @classmethod
    def parse_command_line(cls):
        win32serviceutil.HandleCommandLine(cls)

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.stopEvt = win32event.CreateEvent(None, 0, 0, None)  # create generic event
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STOPPED,
                            (self._svc_name_, ''))
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stopEvt)  # raise event

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STARTED,
                            (self._svc_name_, ''))
        # UNCOMMENT ONE OF THESE
        # self.mainthread()
        # self.mainloop()

    # Wait for stopEvt indefinitely after starting thread.
    def mainthread(self):
        print('main start')
        self.server = MyThread()
        self.server.start()
        print('wait for win32event')
        win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
        self.server.exit()
        print('wait for thread')
        self.server.join()
        print('main done')

    # Wait for stopEvt event in loop.
    def mainloop(self):
        print('loop start')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            dummytask_once()
            rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
        print('loop done')


if __name__ == '__main__':
    SMWinservice.parse_command_line()

0

Принятый ответ с использованием win32serviceutilработает, но сложен и усложняет отладку и внесение изменений. Это гораздо проще в использовании NSSM ( Не-сосание Service Manager) . Вы пишете и с комфортом отлаживаете обычную программу на Python, и когда она наконец заработает, вы используете NSSM, чтобы установить ее как службу менее чем за минуту:

Вы запускаете командную строку с повышенными правами (администратор) nssm.exe install NameOfYourServiceи вводите следующие параметры:

  • путь : (например, путь к python.exe C:\Python27\Python.exe)
  • Аргументы : (например, путь к вашему скрипту python c:\path\to\program.py)

Кстати, если ваша программа печатает полезные сообщения, которые вы хотите сохранить в файле журнала, NSSM также может обработать это и многое другое за вас.


Да, это дубликат ответа Адриано. Я поддержал этот ответ и попытался отредактировать его, но после правок я ожидал новый ответ.
ndemou

Как создать виртуальную среду?
Shaik Moeed

0

Этот ответ является плагиатором из нескольких источников на StackOverflow - большинство из них указано выше, но я забыл о других - извините. Это просто, и сценарии работают «как есть». Для выпусков вы тестируете сценарий, затем копируете его на сервер и останавливаете / запускаете соответствующую службу. И он должен работать для всех языков сценариев (Python, Perl, node.js), а также для пакетных сценариев, таких как GitBash, PowerShell, даже старых сценариев летучей мыши DOS. pyGlue - это связующее звено между службами Windows и вашим скриптом.

'''
A script to create a Windows Service, which, when started, will run an executable with the specified parameters.
Optionally, you can also specify a startup directory

To use this script you MUST define (in class Service)
1. A name for your service (short - preferably no spaces)
2. A display name for your service (the name visibile in Windows Services)
3. A description for your service (long details visible when you inspect the service in Windows Services)
4. The full path of the executable (usually C:/Python38/python.exe or C:WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
5. The script which Python or PowerShell will run(or specify None if your executable is standalone - in which case you don't need pyGlue)
6. The startup directory (or specify None)
7. Any parameters for your script (or for your executable if you have no script)

NOTE: This does not make a portable script.
The associated '_svc_name.exe' in the dist folder will only work if the executable,
(and any optional startup directory) actually exist in those locations on the target system

Usage: 'pyGlue.exe [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
        --username domain\\username : The Username the service is to run under
        --password password : The password for the username
        --startup [manual|auto|disabled|delayed] : How the service starts, default = manual
        --interactive : Allow the service to interact with the desktop.
        --perfmonini file: .ini file to use for registering performance monitor data
        --perfmondll file: .dll file to use when querying the service for performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
        --wait seconds: Wait for the service to actually start or stop.
                If you specify --wait with the 'stop' option, the service and all dependent services will be stopped,
                each waiting the specified period.
'''

# Import all the modules that make life easy
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
import win32evtlogutil
import os
from logging import Formatter, Handler
import logging
import subprocess


# Define the win32api class
class Service (win32serviceutil.ServiceFramework):
        # The following variable are edited by the build.sh script
        _svc_name_ = "TestService"
        _svc_display_name_ = "Test Service"
        _svc_description_ = "Test Running Python Scripts as a Service"
        service_exe = 'c:/Python27/python.exe'
        service_script = None
        service_params = []
        service_startDir = None

        # Initialize the service
        def __init__(self, args):
                win32serviceutil.ServiceFramework.__init__(self, args)
                self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
                self.configure_logging()
                socket.setdefaulttimeout(60)

        # Configure logging to the WINDOWS Event logs
        def configure_logging(self):
                self.formatter = Formatter('%(message)s')
                self.handler = logHandler()
                self.handler.setFormatter(self.formatter)
                self.logger = logging.getLogger()
                self.logger.addHandler(self.handler)
                self.logger.setLevel(logging.INFO)

        # Stop the service
        def SvcStop(self):
                self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
                win32event.SetEvent(self.hWaitStop)

        # Run the service
        def SvcDoRun(self):
                self.main()

        # This is the service
        def main(self):

                # Log that we are starting
                servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED,
                                                          (self._svc_name_, ''))

                # Fire off the real process that does the real work
                logging.info('%s - about to call Popen() to run %s %s %s', self._svc_name_, self.service_exe, self.service_script, self.service_params)
                self.process = subprocess.Popen([self.service_exe, self.service_script] + self.service_params, shell=False, cwd=self.service_startDir)
                logging.info('%s - started process %d', self._svc_name_, self.process.pid)

                # Wait until WINDOWS kills us - retrigger the wait for stop every 60 seconds
                rc = None
                while rc != win32event.WAIT_OBJECT_0:
                        rc = win32event.WaitForSingleObject(self.hWaitStop, (1 * 60 * 1000))

                # Shut down the real process and exit
                logging.info('%s - is terminating process %d', self._svc_name_, self.process.pid)
                self.process.terminate()
                logging.info('%s - is exiting', self._svc_name_)


class logHandler(Handler):
        '''
Emit a log record to the WINDOWS Event log
        '''

        def emit(self, record):
                servicemanager.LogInfoMsg(record.getMessage())


# The main code
if __name__ == '__main__':
        '''
Create a Windows Service, which, when started, will run an executable with the specified parameters.
        '''

        # Check that configuration contains valid values just in case this service has accidentally
        # been moved to a server where things are in different places
        if not os.path.isfile(Service.service_exe):
                print('Executable file({!s}) does not exist'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        if not os.access(Service.service_exe, os.X_OK):
                print('Executable file({!s}) is not executable'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        # Check that any optional startup directory exists
        if (Service.service_startDir is not None) and (not os.path.isdir(Service.service_startDir)):
                print('Start up directory({!s}) does not exist'.format(Service.service_startDir), file=sys.stderr)
                sys.exit(0)

        if len(sys.argv) == 1:
                servicemanager.Initialize()
                servicemanager.PrepareToHostSingle(Service)
                servicemanager.StartServiceCtrlDispatcher()
        else:
                # install/update/remove/start/stop/restart or debug the service
                # One of those command line options must be specified
                win32serviceutil.HandleCommandLine(Service)

Теперь нужно немного отредактировать, и вы не хотите, чтобы все ваши сервисы назывались pyGlue. Итак, есть сценарий (build.sh) для вставки битов и создания настраиваемого «pyGlue» и создания «.exe». Это файл .exe, который устанавливается как служба Windows. После установки вы можете настроить его на автоматический запуск.

#!/bin/sh
# This script build a Windows Service that will install/start/stop/remove a service that runs a script
# That is, executes Python to run a Python script, or PowerShell to run a PowerShell script, etc

if [ $# -lt 6 ]; then
        echo "Usage: build.sh Name Display Description Executable Script StartupDir [Params]..."
        exit 0
fi

name=$1
display=$2
desc=$3
exe=$4
script=$5
startDir=$6
shift; shift; shift; shift; shift; shift
params=
while [ $# -gt 0 ]; do
        if [ "${params}" != "" ]; then
                params="${params}, "
        fi
        params="${params}'$1'"
        shift
done

cat pyGlue.py | sed -e "s/pyGlue/${name}/g" | \
        sed -e "/_svc_name_ =/s?=.*?= '${name}'?" | \
        sed -e "/_svc_display_name_ =/s?=.*?= '${display}'?" | \
        sed -e "/_svc_description_ =/s?=.*?= '${desc}'?" | \
        sed -e "/service_exe =/s?=.*?= '$exe'?" | \
        sed -e "/service_script =/s?=.*?= '$script'?" | \
        sed -e "/service_params =/s?=.*?= [${params}]?" | \
        sed -e "/service_startDir =/s?=.*?= '${startDir}'?" > ${name}.py

cxfreeze ${name}.py --include-modules=win32timezone

Установка - скопируйте '.exe' сервер и скрипт в указанную папку. Запустите .exe от имени администратора с опцией «установить». Откройте службы Windows в качестве администратора и запустите службу. Для обновления просто скопируйте новую версию скрипта и остановите / запустите службу.

Теперь все серверы разные - разные установки Python, разные структуры папок. Я поддерживаю папку для каждого сервера с копией pyGlue.py и build.sh. И я создаю сценарий serverBuild.sh для восстановления всей службы на этом сервере.

# A script to build all the script based Services on this PC
sh build.sh AutoCode 'AutoCode Medical Documents' 'Autocode Medical Documents to SNOMED_CT and AIHW codes' C:/Python38/python.exe autocode.py C:/Users/russell/Documents/autocoding -S -T

-1

https://www.chrisumbel.com/article/windows_services_in_python

  1. Следите за PySvc.py

  2. изменение папки dll

Я знаю, что это старое, но я застрял на этом навсегда. Для меня эта конкретная проблема была решена путем копирования этого файла - pywintypes36.dll

Из -> Python36 \ Lib \ site-packages \ pywin32_system32

Кому -> Python36 \ Lib \ site-packages \ win32

setx /M PATH "%PATH%;C:\Users\user\AppData\Local\Programs\Python\Python38-32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pywin32_system32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\win32
  1. изменение пути к папке python на

cd C:\Users\user\AppData\Local\Programs\Python\Python38-32

  1. NET START PySvc
  2. NET STOP PySvc
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.