ども、「ブログはショートコント」だが持論の初老丸です。
ショートコント…
Python スクリプトを Windows Server でサーヴィスとして動かしたい。
起
まずは
コントは起承転結で。
ひとまず、自分で作った Python スクリプトを Windows Server でサーヴィスとして登録する方法としては以下の二つを見つけた。
- Windows でサーヴィスとして登録する
- honcho を使ってみる(Windows 上で動くか不明確)
Python 製でプロセス監視ツールとして名高い Supervisord は Windows では動作しないようだ。
Supervisor works on just about everything except for Windows. It is tested and supported on Linux, Mac OS X, Solaris, and FreeBSD. It is written entirely in Python, so installation does not require a C compiler.
うむ。
Supervisord だと指定したプロセスが落ちていたら自動で再起動してくれるのが非常に有り難いのだけど、この機能も実装されていると嬉しいなあと思いつつ…
環境
ということで、各種参考記事に掲載されているサンプルを写経しながら以下の環境で試していく。
承(pywin32 を利用する Windows サービスとして登録する)
Python スクリプトをサービスとして登録したい場合には pywin32 を利用すると良いらしい。
参考
- https://gist.github.com/drmalex07/10554232
- http://pywin32.cvs.sourceforge.net/pywin32/pywin32/win32/Demos/service/
- http://nullege.com/codes/search/win32event
ジャパニーズだと以下の記事が参考になった。
masahito.hatenablog.com
有難うございます。
pywin32 のインストール
pywin32 のインストールは pywin32 からダウンロードする。
Python のバージョンを合わせる必要があるので注意する。32bit 版と 64bit 版もあるので注意する。自分はここでスベった。
サービスとして利用するスクリプトサンプル
以下のように写経して動かしてみる
# -*- coding:utf-8 -*- import win32serviceutil import win32service import win32event import servicemanager import socket import time import logging logging.basicConfig( filename = 'c:\oreno-service.log', level = logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s" ) class OrenoSvc (win32serviceutil.ServiceFramework): _svc_name_ = "Oreno-Service01" _svc_display_name_ = "Oreno Service01" # Class の初期化 def __init__(self,args): win32serviceutil.ServiceFramework.__init__(self,args) self.stop_event = win32event.CreateEvent(None,0,0,None) socket.setdefaulttimeout(60) self.stop_requested = False ''' - サービス停止時に呼ばれるメソッド - win32event.SetEvent で win32event.CreateEvent(None,0,0,None) で作成したイベントハンドル(非シグナル)がセットされる ''' def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.stop_event) logging.info('サービスを停止します ...') self.stop_requested = True ''' - サービス開始時に呼ばれるメソッド - servicemanager.LogMsg でログを出力している - main() を呼ぶ ''' def SvcDoRun(self): servicemanager.LogMsg( servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_,'') ) self.main() ''' - 以下に実際の処理を書いていく ''' def main(self): logging.info('Oreno Service を開始します...') while True: if self.stop_requested: logging.info('停止シグナルをうけました: ループを停止します ...') break time.sleep(5) logging.info("コマネチ!! at %s" % time.ctime()) return if __name__ == '__main__': win32serviceutil.HandleCommandLine(OrenoSvc)
引数なしで実行すると以下のように出力される。
PS C:UsersAdministratorDocumentspython> python.exe .o-re-no-service.py Usage: 'o-re-no-service.py [options] install|update|remove|start [...]|stop|restart [...]|debug [...]' Options for 'install' and 'update' commands only: --username domainusername : 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.
ふむふむ。
サービスの登録
サービスの登録は install
オプションを利用する。
PS C:UsersAdministratorDocumentspython> python.exe .o-re-no-service.py install Installing service Oreno-Service01 Service installed
以下のようにサービスが登録されたくさ。
サービスの開始
サービスの開始は start
オプションを利用する。
PS C:UsersAdministratorDocumentspython> python.exe .o-re-no-service.py start Starting service Oreno-Service01
以下のようにサービスが開始されたばい。
今回のサービスは 5 秒ごとにコマネチ!!をログに記録するので、ちゃんとコマネチ!!が記録されているかを確認する。
キタでコマネチ。
サービスの停止
サービスの停止は stop
オプションを利用する。
PS C:UsersAdministratorDocumentspython> python.exe .o-re-no-service.py stop Stopping service Oreno-Service01
以下の通りサービスは停止している。
画像は install
時の使い回しだが、ちゃんとサービスが停止している。
サービスの削除
サービスの削除は remove
オプションを利用する。
PS C:UsersAdministratorDocumentspython> python.exe .o-re-no-service.py remove Removing service Oreno-Service01 Service removed
転(honcho を使ってみる)
honcho とは
pypi.python.org
ドキュメントに記載されているように foreman の Clone として開発されているツール。foreman 同様に複数のプロセスを管理することが出来るライブラリ。
Windows サポートについては以下の通りマージされているようだ。
github.com
honcho インストール
pip で一発。
PS C:UsersAdministratorDocumentspython> pip install honcho Collecting honcho Downloading honcho-0.6.6-py2.py3-none-any.whl Collecting colorama (from honcho) Downloading colorama-0.3.6-py2.py3-none-any.whl Installing collected packages: colorama, honcho Successfully installed colorama-0.3.6 honcho-0.6.6 You are using pip version 7.1.2, however version 8.0.2 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command.
サービスとして利用するサンプルスクリプト
Windows サービスに登録した際のスクリプトを流用。
# -*- coding:utf-8 -*- import time import logging # Referred http://symfoware.blog68.fc2.com/blog-entry-883.html stdout_log = logging.StreamHandler() stdout_log.setLevel(logging.DEBUG) stdout_log.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) file_log = logging.FileHandler(filename = 'c:\oreno-service.log') file_log.setLevel(logging.DEBUG) file_log.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logging.getLogger().addHandler(stdout_log) logging.getLogger().addHandler(file_log) logging.getLogger().setLevel(logging.DEBUG) class OrenoSvc: ''' - 以下に実際の処理を書いていく ''' def main(self): logging.info('Starting Oreno Service ...') try: while True: time.sleep(5) logging.info("Komanechi!! at %s" % time.ctime()) except KeyboardInterrupt: logging.info('stop signal was received : Stopping loop ...') if __name__ == '__main__': ore = OrenoSvc() ore.main()
Procfile を用意する
foreman 同様に Procfile を作成する。
ore: python o-re-no-service02.py
これだけ。
サービスの開始
honcho.exe start
でスタート。
PS C:UsersAdministratorDocumentspython> honcho.exe start 2016-02-07 09:50:09 [2304] [WARNING] Your terminal is not configured to receive UTF-8 encoded text. Please adjust your locale settings or force UTF-8 output by setting PYTHONIOENCODING="utf-8". 09:50:09 system | ore.1 started (pid=2796)
開始すると以下のようなコマンドプロンプトのウィンドウが起動する。
今回はログを stdout にも出力するようにしていたのでログが出力される。
また、run
オプションもあるので start
オプションとの違いについて確認する必要がある。
サービスの停止
サービスの停止は下図のようにコマンドプロンプトのウィンドウを閉じる。
ウィンドウを閉じると以下のようにコマンドプロンプト(今回は PowerShell 上)に出力される。
10:00:04 ore.1 | ^C 10:00:04 system | ore.1 stopped (rc=-1073741510)
ホントにこれしか方法が無いかは引き続き要調査。
動画デモ
こんな感じで動いている。
結
ということで…
Python スクリプトを Windows 上でサービスとして動かす方法を以下の二つの方法でコントしてみた。
- pywin32 を利用してスクリプト自体は Windows サービスに登録する
- 独自のプロセス管理ツール(honcho)を利用する
どっちが良いか
Windows なら特に理由がなければ Windows サービスへの登録の方が良さそうな気がする。理由は単純で Windows サービス管理下にある為、何か問題があった場合等は Event Viewer で状態を確認することが出来る(スクリプト内から Event ログを吐くことも当然出来る)為。但し、お手軽にサービスとして動かしたいとか、pywin32 の処理をスクリプトに含めるのが面倒等の場合には honcho でも良さそうな気がする。
あと、Windows サービスも honcho も Supervisord のようにプロセスが停止していたら叩き起こしてくれるような処理は独自に実装が必要なのは注意が必要。
以上。
元記事はこちら
「自分で作った Python スクリプトを Windows Server にサーヴィスとして登録するショートコント(1)」