原理说明
在Remind-You中,每个plugin都对应着一个进程。主进程在启动后,从配置文件中读取当前有多少个插件。并依次启动这些插件。后续plugin进程退出后,主进程都会重新生成plugin进程。
代码位置
可以在github上找到第一天的代码。https://github.com/bymzy/remind-you/tree/day1
文件结构
[root@bymzy remind-you]# tree
.
├── __init__.py
├── main.py
├── plugins
│ ├── conf.json
│ ├── dict_plugin.py
│ ├── dict_plugin.pyc
│ ├── __init__.py
│ └── __init__.pyc
├── scheduler.py
├── scheduler.pyc
└── setup.py
在第一天的工作中,比较重要的文件有,main.py, scheduler.py, dict_plugin.py以及conf.json。启动conf.json需要被拷贝到/etc/scheduler.py。
依赖的环境及库
使用python2.7运行。
- mulitprocessing
该库提供了方法,可以一某个函数为目标,生成一个进程执行。返回的进程对象,的start方法用来启动该进程;is_alive方法用来判断进程是否已经退出。
process = multiprocessing.Process(target=func, args=(arg))
process.start()
process.is_alive()
- importlib
在Remind-You中,需要支持动态的添加插件。使用importlib可以根据字符串导入lib。
module = importlib('dict_plugin.py')
主要代码
CONF_FILE = '/etc/scheduler.conf'
def parse_config(conf):
with open(conf, 'r') as f:
data = f.read()
return json.loads(data)
def run_plugin(plugin):
name = plugin.get('name')
fileName = plugin.get('fileName')
desc = plugin.get('desc')
arg = plugin.get('args')
module = importlib.import_module('plugins.' + fileName)
process = multiprocessing.Process(target=module.run, args=(arg,))
process.start()
return process
def scheduler_loop():
print 'main process pid: %u' % os.getpid()
conf_dict = parse_config(CONF_FILE)
process_list = []
for plugin in conf_dict.get('plugins', []):
process_list.append((plugin, run_plugin(plugin)))
# monitor process
while True:
to_add = []
to_del = []
for proc in process_list:
if not proc[1].is_alive():
proc[1].join()
to_add.append((proc[0], run_plugin(proc[0])))
to_del.append(proc)
for proc in to_del:
process_list.remove(proc)
to_del = []
for proc in to_add:
process_list.append(proc)
to_add = []
time.sleep(2)
dict_plugin.py 代码示例
import time
import os
import requests
def run(args):
print 'my pid is: %u ' % os.getpid()
time.sleep(3)
plugin代码比较简单,只有一个run函数打印自己的pid,然后等待3s退出。这样做事为了模拟,主进程将plugin进程拉起的情况。
配置文件示例
{
"plugins": [
{
"name": "dict",
"desc": "help you remember English words",
"fileName": "dict_plugin",
"args": "test"
}
]
}
代码说明
- 在main.py中,执行scheduler_loop()方法。这个方法首先从配置文件中读取所有的插件。当前只有一个dict插件,插件fileName字段描述有该插件代码所在的文件,插件代码中默认的run函数为插件的运行函数。
- 使用importlib将插件import进主进程,然后使用multiprocessing.Process生成一个新的进程并调用Start启动。
- 主进程当前页比较简单,循环的判断插件进程是否退出。如果退出,则继续生成一个插件进程。
最终执行效果如下
执行main.py后,插件进程定时退出,然后重新被拉起。