目标:
最近用python bottle写了一些api,但是阿里的服务器有时候会自动重启,导致api挂掉,所以有了写一个自启动服务的打算。
想法:
因为以前写的自启动和保护服务都是用C++写的服务,由于换了公司,电脑上也没有了vs,懒得装,查了下资料,发现python也能写成服务,就打算用python实现。
正题:
一:python实现服务
需要安装pywin32,因为我用的是python2.7,就下了pywin32-218.win-amd64-py2.7.exe,下载安装请百度。以下是服务整体的代码:
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "PythonAutoRunServer"
_svc_display_name_ = "PythonAutoRunServer"
_svc_description_ = "用于Python服务的自启动和监测"
_svc_description_ = _svc_description_.decode('utf8').encode('gbk')
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.logger = self._getLogger()
self.run = True
def _getLogger(self):
logger = logging.getLogger('[PythonService]')
this_file = inspect.getfile(inspect.currentframe())
dirpath = os.path.abspath(os.path.dirname(this_file))
handler = logging.FileHandler(os.path.join(dirpath, "service.log"))
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
def SvcDoRun(self):
import time
# server_type: 1 后台管理系统; 2 东篱服务
server_name = ["", "后台管理系统", "东篱"]
server_type = 1
self.logger.info("service is run....")
start_server_time = 0 # 连续自启动三次时发邮件警报
while self.run:
try:
if python_run_manage.start_check(server_type) == 1:
start_server_time += 1
else:
start_server_time = 0
if start_server_time == 3:
# 发送邮件警报
send_mail.send_auth_mail().send_mail_action("服务器警报", server_name[server_type],
"服务器服务重启次数异常")
time.sleep(60)
except Exception, e:
self.logger.info(str(e))
self.logger.info("sssss")
time.sleep(60)
self.logger.info("---------- svcdorun end --------------")
def SvcStop(self):
self.logger.info("service is stop....")
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.run = False
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(PythonService)
因为以前写的自启动和保护服务都是用C++写的服务,由于换了公司,电脑上也没有了vs,懒得装,查了下资料,发现python也能写成服务,就打算用python实现。
正题:
一:python实现服务
需要安装pywin32,因为我用的是python2.7,就下了pywin32-218.win-amd64-py2.7.exe,下载安装请百度。以下是服务整体的代码:
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "PythonAutoRunServer"
_svc_display_name_ = "PythonAutoRunServer"
_svc_description_ = "用于Python服务的自启动和监测"
_svc_description_ = _svc_description_.decode('utf8').encode('gbk')
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.logger = self._getLogger()
self.run = True
def _getLogger(self):
logger = logging.getLogger('[PythonService]')
this_file = inspect.getfile(inspect.currentframe())
dirpath = os.path.abspath(os.path.dirname(this_file))
handler = logging.FileHandler(os.path.join(dirpath, "service.log"))
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
def SvcDoRun(self):
import time
# server_type: 1 后台管理系统; 2 东篱服务
server_name = ["", "后台管理系统", "东篱"]
server_type = 1
self.logger.info("service is run....")
start_server_time = 0 # 连续自启动三次时发邮件警报
while self.run:
try:
if python_run_manage.start_check(server_type) == 1:
start_server_time += 1
else:
start_server_time = 0
if start_server_time == 3:
# 发送邮件警报
send_mail.send_auth_mail().send_mail_action("服务器警报", server_name[server_type],
"服务器服务重启次数异常")
time.sleep(60)
except Exception, e:
self.logger.info(str(e))
self.logger.info("sssss")
time.sleep(60)
self.logger.info("---------- svcdorun end --------------")
def SvcStop(self):
self.logger.info("service is stop....")
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.run = False
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(PythonService)
需要安装pywin32,因为我用的是python2.7,就下了pywin32-218.win-amd64-py2.7.exe,下载安装请百度。以下是服务整体的代码:
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "PythonAutoRunServer"
_svc_display_name_ = "PythonAutoRunServer"
_svc_description_ = "用于Python服务的自启动和监测"
_svc_description_ = _svc_description_.decode('utf8').encode('gbk')
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.logger = self._getLogger()
self.run = True
def _getLogger(self):
logger = logging.getLogger('[PythonService]')
this_file = inspect.getfile(inspect.currentframe())
dirpath = os.path.abspath(os.path.dirname(this_file))
handler = logging.FileHandler(os.path.join(dirpath, "service.log"))
formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
def SvcDoRun(self):
import time
# server_type: 1 后台管理系统; 2 东篱服务
server_name = ["", "后台管理系统", "东篱"]
server_type = 1
self.logger.info("service is run....")
start_server_time = 0 # 连续自启动三次时发邮件警报
while self.run:
try:
if python_run_manage.start_check(server_type) == 1:
start_server_time += 1
else:
start_server_time = 0
if start_server_time == 3:
# 发送邮件警报
send_mail.send_auth_mail().send_mail_action("服务器警报", server_name[server_type],
"服务器服务重启次数异常")
time.sleep(60)
except Exception, e:
self.logger.info(str(e))
self.logger.info("sssss")
time.sleep(60)
self.logger.info("---------- svcdorun end --------------")
def SvcStop(self):
self.logger.info("service is stop....")
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.run = False
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(PythonService)
这个服务是我百度找到的,其中send_mail是我的邮件通知模块,python_run_manage是具体监听进程是否正在运行的模块。
服务的安装等命令
1. 在环境中安装 pywin32-218.win-amd64-py2.7
2. 管理员启动的cmd中安装 python PythonAutoRunServer.py --startup auto install
3. 启动服务 python PythonAutoRunServer.py start
ps:
1. 关闭服务: python PythonAutoRunServer.py stop
2. 删除服务: python PythonAutoRunServer.py remove
二. 监听进程模块
先贴下完整的代码:
# 目标是 监测需要持续运行的Python程序,当没有运行时,自动启动
import httplib
import json
import subprocess
#可用于检测程序是否正常,通过端口能否连接判断
# def check_aliveness(ip, port, process_name):
# sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# sk.settimeout(1)
# try:
# sk.connect((ip, port))
# print '%s %s %d service is OK!' % (process_name, ip, port)
# aliveness = True
# except Exception:
# print '%s %s %d service is NOT OK!' % (process_name, ip, port)
# # 自启动
# _start_py(_get_py_path(process_name))
# aliveness = False
# finally:
# sk.close()
# return aliveness
import time
import logger
def check_aliveness(ip_port, process_name):
need_start = 0
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
conn = httplib.HTTPConnection(ip_port)
try:
conn.request("POST", "/test_connection", json.dumps({}), headers=headers)
response = conn.getresponse()
data = response.read()
except Exception, e:
pass
aliveness = False
try:
json_data = json.loads(data)
error_code = int(json_data["error"])
if error_code == 200:
aliveness = True
except Exception, e:
aliveness = False
print e
if not aliveness:
# 自启动
need_start = 1
_write_log(process_name + " is not ok")
_start_py(_get_py_path(process_name))
else:
_write_log(process_name + " is ok")
return need_start
# 存储需要监控的py路径
def _get_py_path(process_name):
if process_name == "back_manage":
return r"D:/PythonServer/back_manager/route_for_back_manager.py"
elif process_name == "dongli":
return r"D:/web/python/route_dongli.py"
elif process_name == "dongli_achievement":
return r"D:/web/python/achievement_server.py"
# 启动py程序
def _start_py(path):
try:
cmd = "python %s" % path
cwd = path[0:path.rindex("/")]
subprocess.Popen(cmd,
creationflags=subprocess.CREATE_NEW_CONSOLE,
cwd=cwd)
except Exception, e:
print e
def _write_log(content):
logger.Logger(logger="auto_server", message=content)
# 开始检测
def start_check(check_type):
if check_type == 1:
# 后台管理系统
return check_aliveness('127.0.0.1:4002', "back_manage")
elif check_type == 2:
# 东篱
need_start_one = check_aliveness('127.0.0.1:4000', "dongli")
need_start_two = check_aliveness('127.0.0.1:4001', "dongli_achievement")
if need_start_one == 0 and need_start_two == 0:
return 0
else:
return 1
由服务循环调用start_check,来监测进程。本来是打算用socket来判断服务能否telnet来判断服务是否正常,后来尝试时发现,bottle写的api不能socket,一开始会显示正常,但是你不断开socket就会导致api阻塞,那个时候就会无法ping通…恩,然后就会重启n多的进程,惨惨惨,当然也是我没有把进程写成单例的原因。所以,我在进程中多加了一个test_connection 的api,用来判断进程是否正常。
在_get_py_path方法中保存了进程可执行程序的路径,恩,其实我觉得应该把这些写到cfg文件里会好些,嘛,以后再说~
_start_py方法是用cmd启动python api的方法,CREATE_NEW_CONSOLE这个属性是新开启界面,不过因为是服务启动的进程,所以不会有界面显示~



