qshinoの日記

Powershell関係と徒然なこと

python service on win32

概要

pywin32 を使用し、python でサービスを実装する。

不完全なベースクラスWsvcと、Wsvcを継承し機能を実装するサービスクラスSoneの2つを作成する。

サービスに関わる作業一覧

  • 準備 pip install pywin32
  • 登録 sone.py install
  • 更新 sone.py update
  • 停止 net stop Sone
  • GUI mmc Services.msc

サービス・クラスSone

#!/usr/bin/python3
# 
# sone.py
#
from time import sleep
from wsvc import Wsvc

import logging

 logging.basicConfig( 
  filename = 'c:\\sone.log', 
  level = logging.DEBUG, 
  format = '[service-one] %(levelname)-7.7s %(message)s')


class Sone(Wsvc):
 _svc_name_         = "Sone"
 _svc_display_name_ = "Service 1" 
 _svc_description_  = "Enjoy!" 

  def start(self): 
    self.isrunning = True 
  def stop(self): 
    self.isrunning = False 
  def main(self):
    while self.isrunning: 
      logging.info('sone main.')
      sleep(5)

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

ベース・クラスWsvc

#!/usr/bin/python3
#
# wsvc.py
#
import socket 
import win32serviceutil 
import servicemanager 
import win32event 
import win32service 

class Wsvc(win32serviceutil.ServiceFramework): 
  '''Base class to create winservice in Python''' 
  _svc_name_ = 'pythonService'
  _svc_display_name_ = 'Python Service'
  _svc_description_ = 'Python Service Description' 

  @classmethod 
  def parse_command_line(cls): 
    ''' ClassMethod to parse the command line '''
   win32serviceutil.HandleCommandLine(cls) 

  def __init__(self, args): 
    ''' Constructor of the winservice '''
     win32serviceutil.ServiceFramework.__init__(self, args) 
    self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
    socket.setdefaulttimeout(60) 
    
    def SvcStop(self):
      ''' Called when the service is asked to stop ''' 
     self.stop()   
   self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) win32event.SetEvent(self.hWaitStop) 

  def SvcDoRun(self): 
    ''' Called when the service is asked to start ''' 
    self.start()
   servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')) 

    self.main()
    
  def start(self):
     ''' Override to add logic before the start eg. running condition ''' 
    pass 

  def stop(self): 
    ''' Override to add logic before the stop eg. invalidating running condition ''' 
    pass 

  def main(self): 
    ''' Main class to be ovverridden to add logic ''' 
    pass 

# entry point of the module: copy and paste into the new module 
# ensuring you are calling the "parse_command_line" of the new created class 

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