Як запускати скрипт Python як службу в Windows?


260

Я малюю архітектуру для набору програм, які діляться різними взаємопов'язаними об'єктами, що зберігаються в базі даних. Я хочу, щоб одна з програм виконувала роль служби, яка забезпечує інтерфейс більш високого рівня для операцій над цими об'єктами, а інші програми отримують доступ до об'єктів через цю службу.

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

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

Редагувати: Дякую за всі відповіді поки що, вони досить вичерпні. Я хотів би знати ще одне: як Windows знає про мою службу? Чи можу я керувати ним за допомогою рідних утиліт Windows? Який еквівалент розміщенню сценарію старту / зупинки в /etc/init.d?


2
Перевірте цей шаблон служби Windows, в якому використовується API win32service .
CMS

Відповіді:


254

Так, ти можеш. Я роблю це за допомогою бібліотек 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методі


21
Після цього кодування, як мені сказати Windows запускати це як послугу?
Кіт

33
@Kit: запустіть свій скрипт із командного рядка з параметром "встановити". Тоді ви зможете побачити свою програму у списку служб Windows, де ви можете її запустити, зупинити або встановити для автоматичного запуску
Рікардо Реєс,

16
Ви спеціально згадуєте pythoncom, і ви імпортуєте його у свій приклад код. Проблема полягає в тому, що ви ніколи фактично не використовуєте pythoncom ніде у вашому прикладі коду, ви лише імпортуєте його. Чому варто згадувати про це, а потім не показувати його використання?
Кнопки840

10
Чому для socket.setdefaulttimeout(60)є? Потрібна вона для послуги чи вона просто випадково скопійована з якоїсь існуючої служби? :)
Тимур

7
chrisumbel.com/article/windows_services_in_python Цей подібний приклад, але більш повний
csprabala

41

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

Я натрапив на чудового менеджера послуг , що не всмоктує , який зробив дійсно просте та розумне спілкування із службами Windows. Я зрозумів, що, оскільки я можу передати параметри встановленому сервісу, я міг так само добре вибрати свій виконуваний файл Python і передати свій скрипт як варіант.

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


Будь-яка удача? Я будую дуже простий сайт для клієнта і не потрібно використовувати весь стек Apache. Також побудова сервісу самостійно звучала як запрошення для неприємностей, як я читав з інших коментарів.
Яран

Так, це працює, і це дуже легко зробити. Ви просто даєте шлях та аргументи для сценарію. Мені вдалося змусити мене виконати консоль на випадок, якщо хтось якось опиниться у вікні консолі.
kmcguire

Хоча це, мабуть, працює, є й інші труднощі, особливо коли вам "не потрібно використовувати весь стек Apache": наприклад, gunicorn ще не працює у Windows, що насправді було шоустоппером для мене.
mknaf

4
Хитрість тут - запустити python.exe як службу, а ваш сценарій python як параметр: як "nssm встановити MyServiceName c: \ python27 \ python.exe c: \ temp \ myscript.py"
poleguy

Чудово працює! У системі з декількома віртуальними середовищами шлях може посилатися на інтерпретатор exe Python в каталозі Scripts потрібного віртуального середовища. Схоже, що new-serviceв PowerShell слід це зробити, але запуск (і моніторинг) сценарію як служби, очевидно, включає в себе набагато більше деталей, про що nssm дуже добре піклується.
Фред Шлайфер

26

Найпростіший спосіб - використовувати: NSSM - менеджер служби, що не відсмоктує:

1 - зробити завантаження на https://nssm.cc/download

2 - встановити програму python як послугу: Win prompt як адміністратор

c:> nssm.exe встановити WinService

3 - На консолі NSSM:

шлях: C: \ Python27 \ Python27.exe

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

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

4 - перевірте створені сервіси на services.msc


Раніше я використовував nssm.exe для встановлення своєї Visual Studio C ++ .exe як сервіс, а тепер я можу використовувати nssm.exe і для свого Python .pyc як сервіс. Дякую.
etoricky

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

Як забезпечити віртуальне середовище?
shaik moeed

24

Найпростіший спосіб досягти цього - використовувати натисну команду 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, як передавати параметри контексту?

Я думаю, це проблема із самою вашою командою чи програмою. У будь-якому випадку, перевірте цю підтримку.microsoft.com
en-us/help/886695/…

Мій додаток працює чудово поза службою, і я використав той самий код вище, без результату.
nimeresam

Як забезпечити віртуальне середовище?
shaik moeed

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

1
Це не працює. Служба Windows повинна відкрити певний інтерфейс, який робить пакет pywin32. Однак простого старого сценарію Python буде недостатньо.
Сіддхартха Ганді

23

Існує кілька альтернатив для установки в якості сервісу практично будь-якого виконуваного Windows.

Спосіб 1: Використовуйте instsrv та srvany від rktools.exe

Для Windows Home Server або Windows Server 2003 (також працює з WinXP), Інструменти набору ресурсів Windows Server 2003 поставляються з утилітами, які можна використовувати в тандемі для цього, звані instsrv.exe і srvany.exe . Дивіться цю статтю Microsoft KB KB137890 для отримання детальної інформації про використання цих утиліт.

Для домашнього сервера Windows існує чудова обгортка, зручна для користувачів, для цих утиліт, названа влучно « Будь-який сервісний інсталятор ».

Спосіб 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.

Після моєї первинної відповіді я помітив, що там уже були опубліковані тісно пов'язані запитання та відповіді. Дивитися також:

Чи можу я запустити сценарій Python як службу (в Windows)? Як?

Як зробити так, щоб Windows дізнався про службу, яку я написав на Python?


Я просто зауважив , що і інші подібні Q & вже: stackoverflow.com/questions/32404 / ... stackoverflow.com/questions/34328 / ...
POPCNT

Сервіс-інсталятор не працює над 64-бітовою архітектурою, тому варіант 1 стає опцією goto.
Ной Кемпбелл

Наведене вище посилання на ServiceInstaller більше не працює. Я знайшов це тут: sites.google.com/site/conort/…
LarsH

2
Зауважте, я не думаю, що це NTбуло б обов'язково "всупереч" назві, принаймні, не в народній програмістській промові. Він просто відноситься до " архітектури NT ", на відміну від " марки NT ". Однак, якщо говорити у вікіпедії, це питання дискусійне, оскільки "це не офіційний термін Microsoft", але все ж є традиція з такою думкою.
n611x007

15

Покрокове пояснення, як змусити його працювати:

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 створити TestService binpath = "C: \ Python36 \ Python.exe c: \ PythonFiles \ AppServerSvc.py" DisplayName = "TestService" start = auto

перший аргумент binpath - шлях python.exe

Другий аргумент binpath - це шлях вашого файлу python, який ми вже створили

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

Тоді, якщо все в порядку, ви повинні побачити

[SC] Створити сервісний успіх

Тепер ваша служба python зараз встановлена ​​як служба Windows. Ви можете побачити його в диспетчері сервісів та реєстрі під:

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ TestService

3- Ок зараз. Ви можете розпочати свою послугу у менеджера послуг.

Ви можете виконати кожен файл python, який надає цей сервісний скелет.


Існує маса поганих прикладів використання SetEvent(self.hWaitStop)та використання WaitForSingleObject. Мабуть, на основі бездумного копіювання обраної відповіді. Це хороший спосіб зробити це, який працює чисто для обох "налагодження" аргументів "стоп". (Частина про використання SC здається зайвою, коли HandleCommandLineвиконує роботу, і може запустити налагодження.)
Alias_Knagg

3

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
Хтось знає, чому це отримало протизаконний зв'язок? Це виглядає як приємне рішення.
Jarrod Chesney

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, як було запропоновано у цій відповіді . На нього було дуже легко мігрувати.


2

nssm в python 3+

(Я перетворив .py-файл у .exe з pyinstaller )

nssm: як говорилося раніше

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

    шлях: шлях \ до \ ваш \ program.exe

    Каталог запуску: шлях \ до \ вашої # # як шлях, але без програми.exe

    Аргументи: порожні

Якщо ви не хочете конвертувати проект у .exe

  • створити .bat файл за допомогою python {{your python.py file name}}
  • і встановити шлях до файлу .bat

Як забезпечити віртуальне середовище?
shaik moeed

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і ви заповнюєте ці параметри:

  • path : (шлях до python.exe, наприклад C:\Python27\Python.exe)
  • Аргументи : (шлях до вашого сценарію python, наприклад c:\path\to\program.py)

До речі, якщо ваша програма друкує корисні повідомлення, які ви хочете зберегти у файлі журналу, NSSM також може обробити це та багато іншого для вас.


Так, це дублікат відповіді Адріано. Я підтримав цю відповідь і спробував її відредагувати, але після редагування я шукав нову відповідь.
ndemou

Як забезпечити віртуальне середовище?
shaik moeed

0

Для всіх, хто хоче створити сервіс у VENV або Pycharm !!!!!!!

Прочитавши всі примхи і створивши кілька сценаріїв, якщо ви можете запустити python service.py installі python service.py debug, але python service.py startвідповіді немає.

Можливо, це викликано проблемою venv, адже служба Windows запускає вашу послугу exec PROJECT\venv\Lib\site-packages\win32\pythonservice.exe.

Ви можете скористатись powershellабо cmdпротестувати свою послугу, щоб знайти більше інформації про помилку.

PS C:\Users\oraant> E:

PS E:\> cd \Software\PythonService\venv\Lib\site-packages\win32

PS E:\Software\PythonService\venv\Lib\site-packages\win32> .\pythonservice.exe -debug ttttt
Debugging service ttttt - press Ctrl+C to stop.
Error 0xC0000004 - Python could not import the service's module

Traceback (most recent call last):
  File "E:\Software\PythonService\my_service.py", line 2, in <module>
    import win32serviceutil
ModuleNotFoundError: No module named 'win32serviceutil'

(null): (null)

Якщо ви отримаєте якусь помилку, як я, то ви можете перевірити мою відповідь в іншому запитанні, я її виправив і опублікував тут свій код .


-1

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

  1. Слідкуйте за PySvc.py

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

Я знаю, що це старе, але я на цьому назавжди застряг. Для мене цю конкретну проблему було вирішено шляхом копіювання цього файлу - pywintypes36.dll

З -> Python36 \ Lib \ site-пакети \ pywin32_system32

До -> Python36 \ Lib \ сайт-пакети \ 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.