用Python实现服务器中只重载被修改的进程的方法


Posted in Python onApril 30, 2015

现在,我们已经把一个Web App的框架完全搭建好了,从后端的API到前端的MVVM,流程已经跑通了。

在继续工作前,注意到每次修改Python代码,都必须在命令行先Ctrl-C停止服务器,再重启,改动才能生效。

在开发阶段,每天都要修改、保存几十次代码,每次保存都手动来这么一下非常麻烦,严重地降低了我们的开发效率。有没有办法让服务器检测到代码修改后自动重新加载呢?

Django的开发环境在Debug模式下就可以做到自动重新加载,如果我们编写的服务器也能实现这个功能,就能大大提升开发效率。

可惜的是,Django没把这个功能独立出来,不用Django就享受不到,怎么办?

其实Python本身提供了重新载入模块的功能,但不是所有模块都能被重新载入。另一种思路是检测www目录下的代码改动,一旦有改动,就自动重启服务器。

按照这个思路,我们可以编写一个辅助程序pymonitor.py,让它启动wsgiapp.py,并时刻监控www目录下的代码改动,有改动时,先把当前wsgiapp.py进程杀掉,再重启,就完成了服务器进程的自动重启。

要监控目录文件的变化,我们也无需自己手动定时扫描,Python的第三方库watchdog可以利用操作系统的API来监控目录文件的变化,并发送通知。我们先用easy_install安装:

$ easy_install watchdog

利用watchdog接收文件变化的通知,如果是.py文件,就自动重启wsgiapp.py进程。

利用Python自带的subprocess实现进程的启动和终止,并把输入输出重定向到当前进程的输入输出中:

#!/usr/bin/env python
import os, sys, time, subprocess

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

def log(s):
  print '[Monitor] %s' % s

class MyFileSystemEventHander(FileSystemEventHandler):
  def __init__(self, fn):
    super(MyFileSystemEventHander, self).__init__()
    self.restart = fn

  def on_any_event(self, event):
    if event.src_path.endswith('.py'):
      log('Python source file changed: %s' % event.src_path)
      self.restart()

command = ['echo', 'ok']
process = None

def kill_process():
  global process
  if process:
    log('Kill process [%s]...' % process.pid)
    process.kill()
    process.wait()
    log('Process ended with code %s.' % process.returncode)
    process = None

def start_process():
  global process, command
  log('Start process %s...' % ' '.join(command))
  process = subprocess.Popen(command, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)

def restart_process():
  kill_process()
  start_process()

def start_watch(path, callback):
  observer = Observer()
  observer.schedule(MyFileSystemEventHander(restart_process), path, recursive=True)
  observer.start()
  log('Watching directory %s...' % path)
  start_process()
  try:
    while True:
      time.sleep(0.5)
  except KeyboardInterrupt:
    observer.stop()
  observer.join()

if __name__ == '__main__':
  argv = sys.argv[1:]
  if not argv:
    print('Usage: ./pymonitor your-script.py')
    exit(0)
  if argv[0]!='python':
    argv.insert(0, 'python')
  command = argv
  path = os.path.abspath('.')
  start_watch(path, None)

一共50行左右的代码,就实现了Debug模式的自动重新加载。用下面的命令启动服务器:

$ python pymonitor.py wsgiapp.py

或者给pymonitor.py加上可执行权限,启动服务器:

$ ./pymonitor.py wsgiapp.py

在编辑器中打开一个py文件,修改后保存,看看命令行输出,是不是自动重启了服务器:

$ ./pymonitor.py wsgiapp.py 
[Monitor] Watching directory /Users/michael/Github/awesome-python-webapp/www...
[Monitor] Start process python wsgiapp.py...
...
INFO:root:application (/Users/michael/Github/awesome-python-webapp/www) will start at 0.0.0.0:9000...
[Monitor] Python source file changed: /Users/michael/Github/awesome-python-webapp/www/apis.py
[Monitor] Kill process [2747]...
[Monitor] Process ended with code -9.
[Monitor] Start process python wsgiapp.py...
...
INFO:root:application (/Users/michael/Github/awesome-python-webapp/www) will start at 0.0.0.0:9000...
Try
Python 相关文章推荐
深入解析Python中的WSGI接口
May 11 Python
Django中间件实现拦截器的方法
Jun 01 Python
Python下调用Linux的Shell命令的方法
Jun 12 Python
使用python中的in ,not in来检查元素是不是在列表中的方法
Jul 06 Python
python正则表达式之对号入座篇
Jul 24 Python
Python实现的序列化和反序列化二叉树算法示例
Mar 02 Python
Apache,wsgi,django 程序部署配置方法详解
Jul 01 Python
python实现机器人卡牌
Oct 06 Python
python实现npy格式文件转换为txt文件操作
Jul 01 Python
浅析Python打包时包含静态文件处理方法
Jan 15 Python
python 图像增强算法实现详解
Jan 24 Python
利用Python实时获取steam特惠游戏数据
Jun 25 Python
python同时给两个收件人发送邮件的方法
Apr 30 #Python
python通过邮件服务器端口发送邮件的方法
Apr 30 #Python
在Python的web框架中中编写日志列表的教程
Apr 30 #Python
python登录pop3邮件服务器接收邮件的方法
Apr 30 #Python
python通过smpt发送邮件的方法
Apr 30 #Python
在Python的web框架中编写创建日志的程序的教程
Apr 30 #Python
用Python实现web端用户登录和注册功能的教程
Apr 30 #Python
You might like
PHP 命令行参数详解及应用
2011/05/18 PHP
PHP取二进制文件头快速判断文件类型的实现代码
2013/08/05 PHP
php中各种定义变量的方法小结
2017/10/18 PHP
PHP静态方法和静态属性及常量属性的区别与介绍
2019/03/22 PHP
php解决安全问题的方法实例
2019/09/19 PHP
Javascript+XMLHttpRequest+asp.net无刷新读取数据库数据
2009/08/09 Javascript
jQuery 插件仿百度搜索框智能提示(带Value值)
2013/01/22 Javascript
实现只能输入数字的input不用replace方法
2013/09/12 Javascript
写JQuery插件的基本知识
2013/11/25 Javascript
node.js中的buffer.length方法使用说明
2014/12/14 Javascript
Javascript中的getUTCHours()方法使用详解
2015/06/10 Javascript
vue.js将unix时间戳转换为自定义时间格式
2017/01/03 Javascript
jquery 实现复选框的全选操作实例代码
2017/01/24 Javascript
基于vue.js轮播组件vue-awesome-swiper实现轮播图
2017/03/17 Javascript
详解AngularJS ui-sref的简单使用
2017/04/24 Javascript
javascript input输入框模糊提示功能的实现
2017/09/25 Javascript
JavaScript常用数组操作方法,包含ES6方法
2020/05/10 Javascript
mpvue将vue项目转换为小程序
2018/09/30 Javascript
angularJs提交文本框数据到后台的方法
2018/10/08 Javascript
vue 项目打包时样式及背景图片路径找不到的解决方式
2019/11/12 Javascript
vue使用自定义事件的表单输入组件用法详解【日期组件与货币组件】
2020/06/01 Javascript
微信小程序中的列表切换功能实例代码详解
2020/06/09 Javascript
js+canvas绘制图形验证码
2020/09/21 Javascript
Python中super()函数简介及用法分享
2016/07/11 Python
python实现飞机大战
2018/09/11 Python
pandas对dataFrame中某一个列的数据进行处理的方法
2019/07/08 Python
详解mac python+selenium+Chrome 简单案例
2019/11/08 Python
Python中使用gflags实例及原理解析
2019/12/13 Python
英国领先的男装设计师服装独立零售商:Repertoire Fashion
2020/10/19 全球购物
软件测试工程师笔试题带答案
2015/03/27 面试题
业务员薪酬管理制度
2014/01/15 职场文书
党员批评与自我批评发言稿
2014/10/14 职场文书
2015元旦晚会主持词(开场白+结束语)
2014/12/14 职场文书
酒店员工辞职信范文
2015/02/28 职场文书
2015年卫生局工作总结
2015/07/24 职场文书
公文写作指导之倡议书!
2019/07/03 职场文书