WindowsでサービスとしてPythonスクリプトをどのように実行しますか?


260

データベースに格納された相互に関連するさまざまなオブジェクトを共有する一連のプログラムのアーキテクチャをスケッチしています。プログラムの1つを、これらのオブジェクトの操作に高レベルのインターフェースを提供するサービスとして機能させ、他のプログラムがそのサービスを介してオブジェクトにアクセスするようにしたいと考えています。

私は現在、そのサービスを実装するテクノロジーとしてPythonおよびDjangoフレームワークを目指しています。LinuxでPythonプログラムをデーモン化する方法を理解していると確信しています。ただし、システムがWindowsをサポートする必要があるのは、オプションの仕様項目です。Windowsプログラミングの経験はほとんどなく、Windowsサービスの経験はまったくありません。

PythonプログラムをWindowsサービスとして実行することはできますか(つまり、ユーザーログインなしで自動的に実行します)。私は必ずしもこの部分を実装する必要はありませんが、これらの線に沿って設計するかどうかを決定するために、それがどのように行われるかについて大まかな考えが必要です。

編集:これまでのすべての答えをありがとう、それらは非常に包括的です。私は1つのより多くの事を知っていただきたいと思います:どのようにWindowsは私のサービスを知っているのですか?ネイティブのWindowsユーティリティで管理できますか? /etc/init.dに開始/停止スクリプトを配置するのと同じことは何ですか?


2
win32service APIを使用するこのWindowsサービステンプレートを確認してください。
CMS

回答:


254

はい、できます。私は、ActivePythonに含まれている、またはpywin32(Python for Windows拡張機能)でインストールできるpythoncomライブラリーを使用してそれを行います。

これは単純なサービスの基本的な骨組みです:

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:コマンドラインからパラメーター「install」を指定して、スクリプトを実行します。次に、Windowsのサービスリストにアプリケーションを表示し、アプリケーションを開始、停止、または自動的に開始するように設定できます
Ricardo Reyes

16
pythoncomに特別な言及をし、それをサンプルコードにインポートします。問題は、サンプルコードのどこでも実際にpythoncomを使用することはなく、インポートするだけです。なぜそれを特別に言及し、その使用法を示さないのですか?
Buttons840

10
なぜsocket.setdefaulttimeout(60)ですか?サービスに必要ですか、それとも既存のサービスから誤ってコピーされただけですか?:)
ティムール

7
chrisumbel.com/article/windows_services_in_pythonこれは類似した例ですが、より完全です
csprabala '27

41

私は数週間前に選択した回答に賛成票を投じましたが、その間、私はこのトピックについてさらに苦労しました。特別なPythonのインストールがあり、特別なモジュールを使用してスクリプトをサービスとして実行するのは、単に間違った方法のようです。移植性などはどうですか?

私はすばらしいNon-sucking Service Managerに出くわしました。これにより、Windowsサービスの処理は非常にシンプルで正気になりました。インストールされているサービスにオプションを渡すことができるので、Python実行可能ファイルを選択してスクリプトをオプションとして渡すこともできると考えました。

私はまだこのソリューションを試していませんが、今すぐ試し、プロセスに従ってこの投稿を更新します。私はWindowsでvirtualenvsを使用することにも興味があるので、遅かれ早かれチュートリアルを思いついて、ここにリンクするかもしれません。


運が良ければ?私はクライアント用に非常にシンプルなサイトを構築しており、Apacheスタック全体を使用する必要はありません。また、他のコメントを読んだように、自分でサービスを構築することもトラブルの誘いのように思えます。
Jaran 2014

はい、これは機能し、実行するのは非常に簡単です。スクリプトのパスと引数を指定するだけです。誰かがコンソールウィンドウを表示してしまった場合に備えて、コンソールなしで実行することができました。
kmcguire 2014

これは明らかに機能しますが、特に「Apacheスタック全体を使用する必要がない場合」には他の問題があります。たとえば、gunicornはWindowsではまだ実行されていません。
mknaf 2014

4
ここでの秘訣は、python.exeをサービスとして実行し、Pythonスクリプトをパラメーターとして実行することです。たとえば、「nssm install MyServiceName c:\ python27 \ python.exe c:\ temp \ myscript.py」のようにします
poleguy

よく働く!複数の仮想環境を持つシステムでは、パスは目的の仮想環境のScriptsディレクトリにあるPythonインタープリターexeを参照できます。new-servicePowerShellではこれを実行できるように見えますが、サービスとしてスクリプトを開始(および監視)すると、明らかに多くの詳細が含まれ、nssmが非常に適切に処理します。
Fred Schleifer、2015

26

最も簡単な方法は、以下を使用することです:NSSM-非吸引サービスマネージャ:

1- https://nssm.cc/downloadでダウンロードする

2-Pythonプログラムをサービスとしてインストール:Winプロンプトを管理者として

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にも使用できます。ありがとう。
エトリッキー

注:* .pyスクリプトがスペースのあるフォルダーにある場合(例:C:\ Program Files \ myapp.py)、引用符で引数を指定する必要があります:引数: "C:\ Program Files \ myapp.py"
Yuryコズロフ

仮想環境を提供する方法は?
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でサービスを作成する場合、コンテキストパラメータで渡す方法は?

コマンドやアプリケーション自体の問題だと思います。とにかく、このsupport.microsoft.com/en-us/help/886695/…を
pyOwner '21

私のアプリはサービス外でも問題なく機能し、上記と同じコードを使用しても結果はありませんでした。
nimeresam

仮想環境を提供する方法は?
shaik moeed

virtualenvを試しましたか?
pyOwner

1
これは機能しません。Windowsサービスは、pywin32パッケージが行う特定のインターフェイスを公開する必要があります。ただし、古いPythonスクリプトでは不十分です。
シッダールタガンジー

23

事実上すべてのWindows実行可能ファイルをサービスとしてインストールする方法はいくつかあります。

方法1:rktools.exeのinstsrvとsrvanyを使用する

Windows Home ServerまたはWindows Server 2003(WinXPでも動作します)の場合、Windows Server 2003リソースキットツールには、instsrv.exeおよびsrvany.exeと呼ばれる、これと並行して使用できるユーティリティが付属しています。このMicrosoft KB記事KB137890を参照してください。これらの使用方法の詳細については、を参照してください。

Windows Home Serverには、これらのユーティリティ用の使いやすいラッパーがあり、適切に「Any Service Installer」と名付けられています。

方法2:Windows NT用のServiceInstallerを使用する

Windows NT用ServiceInstallerここからダウンロード可能)を使用して、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に投稿された密接に関連するQ&Aがあることに気付きました。以下も参照してください。

Pythonスクリプトをサービスとして実行できますか(Windowsの場合)?どうやって?

Pythonで作成したサービスをWindowsに認識させるにはどうすればよいですか?


:私はちょうど、他の類似したQ&Aが既に存在しているに気づい stackoverflow.com/questions/32404/...の stackoverflow.com/questions/34328/...
POPCNT

サービスインストーラーは64ビットアーキテクチャーでは機能しないため、オプション1はgotoオプションになります。
ノアキャンベル

上記のServiceInstallerへのリンクは機能しなくなります。私はここでそれを見つけた:sites.google.com/site/conort/...
LarsH

2
余談ですが、NT少なくともプログラマーによるスピーチでは、名前に必ずしも「反する」とは思わないでしょう。「NT ブランド」ではなく、「NT アーキテクチャ」を指すだけです。とは言っても、ウィキペディアの話によると、「これはマイクロソフトの公式用語ではない」ため、これは議論の余地がありますが、それでもこの考え方には伝統があります。
n611x007 14

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 Create TestService binpath = "C:\ Python36 \ Python.exe c:\ PythonFiles \ AppServerSvc.py" DisplayName = "TestService" start = auto

binpathの最初の引数はpython.exeパスです

binpathの 2番目の引数 はすでに作成したPythonファイルのパスです

すべての「=」記号の後に1つのスペースを置く必要があることをお見逃しなく。

次に、すべてが問題なければ、

[SC] CreateService SUCCESS

これで、PythonサービスがWindowsサービスとしてインストールされました。あなたはそれをService Managerとレジストリの下で見ることができます:

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Services \ TestService

3- OKです。サービスマネージャーでサービスを開始できます。

このサービススケルトンを提供するすべてのpythonファイルを実行できます。


そこに使用する方法のうち、悪い例がたくさんありますSetEvent(self.hWaitStop)とはWaitForSingleObject。おそらくここで選択された回答の軽率なコピーに基づいています。これは、「デバッグ」と「停止」の両方の引数で問題なく機能する良い方法です。(HandleCommandLineジョブを実行すると、SCの使用に関する部分は冗長に見え、デバッグを実行できます。)
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
なぜこれが反対票を得たのか誰か知っていますか?それは素晴らしい解決策のように見えます。
ジャロッドチェスニー2017

3

私はpywin32でサービスとしてホスティングを始めました

すべてが順調でしたが、システムの起動時に30秒(Windowsのデフォルトのタイムアウト)以内にサービスを開始できないという問題に遭遇しました。Windowsの起動が1台の物理マシンでホストされている複数の仮想マシンで同時に行われ、IO負荷が非常に大きかったため、これは私にとって重要でした。エラーメッセージは次のとおりです。

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

Python 3 以降のnssm

(私は.pyファイルをpyinstallerで .exeに変換しました

nssm:前述のとおり

  • nssm install {ServiceName}を実行します
  • NSSMのコンソール:

    パス:path \ to \ your \ program.exe

    起動ディレクトリ:path \ to \ your \#パスと同じですが、program.exeはありません

    引数:空

プロジェクトを.exeに変換したくない場合

  • で.batファイルを作成する python {{your python.py file name}}
  • .batファイルへのパスを設定します

仮想環境を提供する方法は?
shaik moeed

1

ループまたはサブスレッドを使用した完全なpywin32の例

これを数日間オンオフに取り組んだ後、私が見つけたいと思っていた答えは、pywin32を使用してそれを美しく自己完結型に保つためです。

これは、1つのループベースのソリューションと1つのスレッドベースのソリューションの完全な動作コードです。私は2.7とWin7でのみ最新バージョンをテストしましたが、Python 2と3の両方で動作する可能性があります。ループはコードのポーリングに適しているはずであり、トレッドはよりサーバーのようなコードで動作するはずです。正常にシャットダウンする標準的な方法がないウェイトレスの 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(吸引サービスマネージャ)を使用する方がはるかに簡単です。通常のpythonプログラムを作成して快適にデバッグし、それが最終的に機能したら、NSSMを使用して1分以内にサービスとしてインストールします。

管理者特権のコマンドプロンプトから実行nssm.exe install NameOfYourServiceし、次のオプションを入力します。

  • path:(python.exeへのパスなどC:\Python27\Python.exe
  • 引数:(Pythonスクリプトへのパスなどc:\path\to\program.py

ちなみに、プログラムがログファイルに保存したい有用なメッセージを出力する場合、NSSMはこれに加えてさらに多くのことを処理できます。


はい、これはアドリアーノの答えの複製です。私はその回答に賛成して編集しようとしましたが、編集後、新しい回答を探していました。
ndemou

仮想環境を提供する方法は?
shaik moeed

0

VENVまたはPycharmでサービスを作成したい人向け!!!!!!!

すべてanwsersを読んだ後、あなたが実行できるかどうか、いくつかのスクリプトを作成python service.py installしてpython service.py debugますが、python service.py start何の応答がありません。

Windowsサービスがexecによってサービスを開始するため、それはvenvの問題が原因である可能性があります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-packages \ pywin32_system32

To-> 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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.