您的位置:首页 > 编程语言 > Python开发

python使用supervisord管理进程

2015-08-25 14:47 716 查看

0×00 Supervisor简介

————————————————————

Supervisor是用Python实现的一款非常实用的进程管理工具,可以方便的通过命令开启、关闭、重启等操作,而且它管理的进程一旦崩溃会自动重启,但是supervisor管理的进程必须由supervisord来启动,并且管理的程序必要是非Daemon程序,Supervisor会帮你把它转化为Daemon程序,比如想要使用Supervisor来管理Nginx进程,就必须在Nginx配置文件中加入 daemon off让Nginx以非Daemon方式运行

0×01 Supervisor安装

————————————————————

Supervisor是基于Python编写,所以可以使用easy_install或 pip来安装,这里使用pip

Shell

1234567891011121314151617181920[root@localhost ~]# yum install python-pip -y[root@localhost ~]# pip install supervisorDownloading/unpacking supervisor Downloading supervisor-3.0.tar.gz (459kB): 459kB downloaded Running setup.py egg_info for package supervisorRequirement already satisfied (use --upgrade to upgrade): distribute in /usr/lib/python2.6/site-packages (from supervisor)Downloading/unpacking meld3>=0.6.5 (from supervisor) Downloading meld3-0.6.10.tar.gz (41kB): 41kB downloaded Running setup.py egg_info for package meld3Installing collected packages: supervisor, meld3 Running setup.py install for supervisor Skipping installation of /usr/lib/python2.6/site-packages/supervisor/__init__.py (namespace package) Installing /usr/lib/python2.6/site-packages/supervisor-3.0-py2.6-nspkg.pth Installing echo_supervisord_conf script to /usr/bin Installing pidproxy script to /usr/bin Installing supervisorctl script to /usr/bin Installing supervisord script to /usr/bin Running setup.py install for meld3Successfully installed supervisor meld3Cleaning up...
安装完成后,supervisor会提供两个命令:
supervisord: 启动supervisor守护进程
supervisorctl: supervisor控制脚本,类似与 service 命令0×02 Supervisor配置
————————————————————
生成配置文件:Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

[root@localhost
~]#
echo_supervisord_conf > /etc/supervisord.conf

[root@localhost
~]#
vim /etc/supervisord.conf

[unix_http_server]

;
定义Socket文件位置

file=/tmp/supervisor.sock

;
WEB管理界面,默认关闭

[inet_http_server]

port=9100
;
默认
127.0.0.1:9001

username=tux

password=123

[supervisord]

logfile=/var/log/supervisord.log

logfile_maxbytes=50MB ;
单个日志大小,
默认
50M,
超过指定大小则进行日志轮询

logfile_backups=10 ;
保留日志数据

loglevel=info
;
可选
debug,warn,trace

pidfile=/var/run/supervisord.pid

nodaemon=false

minfds=1024

minprocs=200

[rpcinterface:supervisor]

supervisor.rpcinterface_factory
=
supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]

;
Socket
文件路径,必须与
unix_http_server中
file
位置一致

serverurl=unix:///tmp/supervisor.sock
;
use
a
unix://
URL for
a
unix
socket

;
管理单个进程配置,
program
后面是服务名称

[program:flask]

command=/opt/verystar/flask/bin/python
runserver.py

process_name=%(program_name)s
;
程序名称

directory=/opt/verystar/
;
程序目录,执行命令前会先进行到此目录

autostart=true ;
supervisord启动时是否自动启动此进程

autorestart=true ;
发生故障时自动重启

startsecs=5
;
5秒内程序必须启动,
默认
1秒

startretries=3 ;
最多
3
次启动失败

stopsignal=QUIT
;
使用QUIT信号来结束进程,默认:
TERM

redirect_stderr=true ;

stderr
重定向到
stdout

stdout_logfile=/var/log/flask-access.log

0×03 简单flask测试脚本

————————————————————

[root@localhost verystar]# vim /opt/verystar/runserver.py

runserver.py

Python

1234567891011121314#!/opt/verystar/flask/bin/python# -*- coding: utf-8 -*-from flask import Flaskapp = Flask(__name__) @app.route('/')@app.route('/<name>')def index(name=None): if not name: name = 'World' return "Hello,%s" % name if __name__ == "__main__": app.run(host='0.0.0.0')

0×04 Supervisor启动及进程管理

————————————————————
启动supervisord守护进程Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

[root@localhost
verystar]#
supervisord -c /etc/supervisord.conf

[root@localhost
verystar]#
supervisorctl status flask

flask RUNNING pid
13306,
uptime
0:00:20

[root@localhost
verystar]#
supervisorctl stop flask

flask:
stopped

[root@localhost
verystar]#
supervisorctl status

flask STOPPED Nov
27
01:04
PM

[root@localhost
verystar]#
supervisorctl start flask

flask:
started

[root@localhost
verystar]#
supervisorctl reload flask

Restarted
supervisord

[root@localhost
verystar]#
curl http://localhost:5000/
Hello,World

[root@localhost
verystar]#
curl http://localhost:5000/tux
Hello,tux

测试:
将flask进程Kill掉,看supervisor是否能将其重启

[root@localhost
verystar]#
kill 13306

[root@localhost
verystar]#
supervisorctl status flask

flask STARTING

[root@localhost
verystar]#
supervisorctl status flask

flask RUNNING pid
13331,
uptime
0:00:08

简单的WEB管理界面





Published in Python, 监控 and tagged daemon, python, supervisor, 进程管理 on 2013
年 11 月 27 日 by 影子

Python+dnspod实现DDNS

没有评论

使用场合,使用ADSL架设的服务器,由于IP不固定可能导致IP改变后服务器将不可用

这里使用Python脚本来实现IP被更改后自动更新Dnspod上的记录

dnspod_ddns for python

Python

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#!/usr/bin/python# -*- coding: utf-8 -*-import urllibimport urllib2import time__author__ = u'戴喜军'current_ip = None # format: domains = {'sub_domain': record_id}domains = { 'ns': 35192771, 'alywb': 41016542, 'company': 41016633, 'office': 35191293, 'verywx': 27714667, 'verywxapi': 41017053, 'weixin': 41017262, 'weixin-adm': 41017138, 'weixin-trans': 41017190, 'yx': 41017337} def ddns(sub_domain, record_id, ip): para = { 'login_email': 'you_email@you_email.com', # 登陆dnspod的账号 'login_password': 'password', # 密码 'domain_id': 2428050, # 域名ID,使用curl -X POST https://dnsapi.cn/Domain.List -d 'login_email=api@dnspod.com&login_password=password&format=json' 获取 'record_line': '电信', # 线路 'sub_domain': sub_domain, # 子域名 'record_id': record_id, # 子域名ID,使用 curl -X POST https://dnsapi.cn/Record.List -d 'login_email=api@dnspod.com&login_password=password&format=json&domain_id=2317346' 获得 'value': ip, # IP 'format': 'json' # 返回的格式,默认为XML格式 } data = urllib.urlencode(para) req = urllib2.Request('https://dnsapi.cn/Record.Ddns', data) req.add_header('Content-type', 'application/x-www-form-urlencoded') req.add_header('Accept', 'text/json') response = urllib2.urlopen(req) return response.read() def getip(): req = urllib2.Request('http://www.linuxyunwei.com/ip.php') ip = urllib2.urlopen(req).read() return ip if __name__ == '__main__': while True: try: ip = getip() if current_ip != ip: current_ip = ip for k, v in domains.items(): print ddns(k, v, ip) except Exception, e: pass time.sleep(300)
Published in Python and tagged ddns, dnspod, python, script on 2013 年 9 月 20 日 by 影子

Python SocksiPy-branch模板的简单应用

没有评论目的: 抓取目标页面内容时不想让服务器记录您真实的IP,或是通过代理服务器抓取墙外的内容
使用模块: http://socksipy-branch.googlecode.com/files/SocksiPy-branch-1.02.tar.gz
PS: SocksiPy模板是没有 wrapmodule方法的, 一定要使用 SocksiPy-branch
测试代码如下sock5代理Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#!/usr/bin/env python

# -*- coding: utf-8 -*-

#=======set default encoding===

import
sys

import
socks

import
urllib2

reload(sys)

sys.setdefaultencoding('utf-8')

# 获取代理前的IP地址

print
urllib2.urlopen('http://www.linuxyunwei.com/ip.php').read()

# 设置代理

socks.setdefaultproxy(proxytype=socks.PROXY_TYPE_SOCKS5,

addr='xx.xx.xx.xx', #
Sock5服务器的IP

port=1080,

rdns=True,

username='',

password='')

socks.wrapmodule(urllib2)

# 获取代理后的IP地址

print
urllib2.urlopen('http://www.linuxyunwei.com/ip.php').read()

本人在测试的时候,发现代理后并不是所有网站都能抓取

Published in Python on 2013 年 8
月 24 日 by 影子

Python中一行代码实现阶乘

没有评论

越来越发现Python真的是无所不能

Python

12345In [2]: reduce(lambda x,y:x+y, range(1,101))Out[2]: 5050 In [3]: reduce(lambda x,y:x*y, range(1,20))Out[3]: 121645100408832000
代码分析:
range(1,101): 产生一个从1到100的列表 [1,2,3,4,5,......,100]
lambda x,y:x+y 生成一个匿名函数,返回x+y的值
reduce(function, seq): python中的reduce内建函数是一个二元操作函数,他用来将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给reduce中的函数 func()(必须是一个二元操作函数)先对集合中的第1,2个数据进行操作,得到的结果再与第三个数据用func()函数运算,最后得到一个结果。Published in Python and tagged lambda, python, range, reduce, 阶乘 on 2013 年 4 月 22 日 by 影子

Linux 下使用pyinotify监视文件更改并发送Email

没有评论场景:使用脚本监视某目录下的文件增、删、改等操作,并将其结果发送Email到指定邮箱,本文只监视了文件被创建的事件
代码如下:Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

#!/usr/bin/env python

#-*- coding: utf-8 -*-

import
os

import
sys

import
smtplib

import
pyinotify

import
mimetypes

from
email.mime.text
import
MIMEText

from
email.mime.image
import
MIMEImage

from
email.mime.multipart
import
MIMEMultipart

reload(sys)

sys.setdefaultencoding('utf8')

def
send_Mail(full_filename):

smtp
=
smtplib.SMTP()

try:

smtp.connect('SMTP服务器地址')

smtp.login('邮箱账号',
'密码')

except
smtplib.SMTPConnectError,
error:

print
error

sys.exit(2)

#
构造MIMEMultipart对象做为根容器

msg
=
MIMEMultipart()

msg['From']
=
u'xxx<发送者邮箱地址>'

msg['To']
=
u'接收者邮箱地址'

msg['Subject']
=
u'邮件标题'

#
构造MIMEText对象做为邮件显示内容并附加到根容器

msg.attach(MIMEText(os.path.basename(full_filename),
'plain',
'utf-8'))

#
构造MIMEImage对象做为文件附件内容并附加到根容器

ctype,
encoding
=
mimetypes.guess_type(full_filename)

if
ctype
is
None
or
encoding
is
not
None:

ctype
=
'application/octet-stream'

maintype,
subtype
=
ctype.split('/',
1)

#
读入文件内容并格式化

try:

data
=
open(full_filename,
'rb')

file_msg
=
MIMEImage(data.read(),
subtype)

except
IOError,
error:

print
error

##
设置附件头

basename
=
os.path.basename(full_filename)

file_msg.add_header('Content-Disposition',
'attachment;filename="%s"'
%
basename)

msg.attach(file_msg)

smtp.sendmail(msg["From"],
msg["To"],
msg.as_string().encode('utf-8'))

smtp.close()

class
EventHandler(pyinotify.ProcessEvent):

def
process_IN_CREATE(self,
event):

#
取事件文件全路径

self.full_name
=
os.path.join(event.path,
event.name)

#
取事件文件后缀名

self.ext
=
os.path.splitext(self.full_name)[1]

#
当匹配到PDF文件时,发送邮件

if
self.ext
==
'.pdf':

send_Mail(self.full_name)

def
main():

#
被监视的目录

path
=
'/disk/share/fax'

wm
=
pyinotify.WatchManager()

notifier
=
pyinotify.ThreadedNotifier(wm,
EventHandler())

#
设置受监视的事件,这里只监视文件创建事件,(rec=True, auto_add=True)为递归处理

wm.add_watch(path,
pyinotify.IN_CREATE,
rec=True,
auto_add=True)

notifier.start()

if
__name__
==
'__main__':

try:

pid
=
os.fork()

if
pid
>
0:

sys.exit(0)

except
OSError,
e:

print
>>sys.stderr,
'fork failed: %d (%s)'
%
(e.errno,
e.strerror)

sys.exit(1)

os.chdir('/tmp')

#
设置程序以daemon方式运行,不依赖于终端

os.setsid()

os.umask(0)

main()

Published in Python, 脚本编程 and tagged Linux, pyinotify, python, smtp, 目录监视 on 2013
年 4 月 2 日 by 影子

sublimetext2
中运行Python提示EOFError: EOF when reading a line

没有评论

要sublimeText2中编译运行Python文件时,如果代码中带有需要用户输入的函数时(raw_input/input)会提示以下错误

EOFError: EOF when reading a line
解决方法:

一、安装sublimeREPL

打开sublimeText2按CTRL+SHIFT+P,英文版输入:install后选择
Package Control: Install Package
;中文版输入:安装软件包

输入sublimeREPL 回车就会自动安装

重启sublimeText2
二、运行Python文件

方法1:CTRL+SHIFT+P 输入:sublimePython-RUN 就可以运行

方法2:菜单【工具】-【sublimePERL】-【Python】-【Python – RUN current file】

Published in Python, 未分类 and tagged Python,sublimetext on 2012
年 11 月 29 日 by 影子

Python 列表中去除重复值

没有评论

Python

1234>>> l = ['a','b','c','b','c',1,2,1,4,2]>>> l = list(set(l))>>> l['a', 1, 'c', 'b', 4, 2]
Published in Python on 2012 年 11 月 19 日 by 影子

nginx+fastcgi 环境webpy重定向问题

没有评论代码片段:Python

1

2

3

4

5

class
add:

def
POST(self):

i
=
web.input()

n
=
db.insert('test',
title=i.title)

raise
web.seeother('/')

以上代码原意是在数据插入以后,重定向到网站根目录,如http://www.domain.com/

但事与愿违,在插入数据以后并没有转到根目录,并且此时URL变成 http://www.domain.com/add/
会在原有的URL末尾加上’/ 此时会提示没有找到文件
解决方法:

在nginx配置文件中添加一行:

fastcgi_param SCRIPT_NAME “”;
网上其他方法(没试过):

Python

1

2

3

4

import
os

home=''

os.environ["SCRIPT_NAME"]
=
home

os.environ["REAL_SCRIPT_NAME"]
=
home

Published in nginx, Python on 2012
年 10 月 17 日 by 影子

使用pygame 播放mp3

没有评论

import pygame

pygame.mixer.init()

pygame.mixer_music.load(r’./1280128564.mp3′)

pygame.mixer.music.play()

pygame.init() 进行全部模块的初始化,

pygame.mixer.init() 或者只初始化音频部分

pygame.mixer.music.load(‘/home/liumin/love.mp3′) 使用文件名作为参数载入音乐 ,音乐可以是ogg、mp3等格式。载入的音乐不会全部放到内容中,而是以流的形式播放的,即在播放的时候才会一点点从文件中读取。

pygame.mixer.music.play()播放载入的音乐。该函数立即返回,音乐播放在后台进行。

play方法还可以使用两个参数

pygame.mixer.music.play(loops=0, start=0.0) loops和start分别代表重复的次数和开始播放的位置。

pygame.mixer.music.stop() 停止播放,

pygame.mixer.music.pause() 暂停播放。

pygame.mixer.music.unpause() 取消暂停。

pygame.mixer.music.fadeout(time) 用来进行淡出,在time毫秒的时间内音量由初始值渐变为0,最后停止播放。

pygame.mixer.music.set_volume(value) 来设置播放的音量,音量value的范围为0.0到1.0。

pygame.mixer.music.get_busy() 判断是否在播放音乐,返回1为正在播放。

pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) 在音乐播放完成时,用事件的方式通知用户程序,设置当音乐播放完成时发送pygame.USEREVENT+1事件给用户程序。 pygame.mixer.music.queue(filename) 使用指定下一个要播放的音乐文件,当前的音乐播放完成后自动开始播放指定的下一个。一次只能指定一个等待播放的音乐文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: