python基于windows自动下拉git代码并重启程序模块。

前言:

笔者最近在搞一个项目,须要把python客户端代码(能够理解成绑定不一样帐号的爬虫吧)部署在20+台windows机器上(之后还会追加新机器)。因为客户机多,并且经常优化、修bug、加功能,使得笔者为了更新代码而不胜其扰!小小的调整竟然要一台台部署(windows只能远程链接,可没办法linux那样同时给多个ssh链接发相同的命令)。因而,笔者测试并开发了一套“基于windows自动下拉git代码并重启程序模块”(笔者不知道该简称什么...大概就是自动更新代码吧)。python

思路:

linux系统就很少说了,只须要git检测到更新后,kill -9 便可,能够根据参数识别,例如 python client_main.py 利用ps筛选出来杀掉便可。linux

windows没有这命令,可是能够根据执行文件名杀掉。例如杀掉名叫 python.exe 的全部进程。这是惟一方法,可是你会把系统下全部的python都干掉,包括基于python的调试工具。git

因而,我想到的方法是用最土的方法,“用标识位告知程序是否有更新,是否要终止,是否要重启”。虽然又土又不帅气,却很实用。特别像我这种客户端必须等一个任务完成后才能终结的,很是合适。一个守护进程检测更新,一个文件标识状态,子进程本身检测标识状态去中止。简简单单的完成了自动化需求。windows

代码:

测试git仓库 : https://gitee.com/kid0/tx 【有须要测试,代码请上传到本身的git上方便测试。固然也能够在本身的git项目中直接引用auto.py下的函数】网络

模块代码(我命名为auto.py)ssh

#-*-coding:utf-8-*-
import os
import time
import codecs
from configparser import ConfigParser
from multiprocessing import Process

local_path = os.path.join(os.getcwd(),'local.txt' )

code_check_time = 10

def set_code_check_time(t=10):
    """
    设置git检测频率,单位秒
    """
    global code_check_time
    code_check_time = t

def auto_manager_main(fun,*args,**kwargs):
    """
    委托进程
    """
    print('主进程PID:',os.getpid())
    global code_check_time
    _code_check_time = code_check_time
    if 1:
        if not os.path.isfile(local_path):
            f = open(local_path,'w+')
            txt = """[local]
need_stop = 0
need_restart = 0"""
            f.write(txt)
            f.close()
    con = ConfigParser()
    con.read_file(codecs.open(local_path,'r+',"utf-8-sig"))
    con.set('local','need_stop','0')
    con.set('local','need_restart','0')
    con.write(open(local_path,'w+'))
    _f = True
    while True:
        con.read_file(codecs.open(local_path,'r+',"utf-8-sig"))
        if not con.get('local','need_stop') == '1':
            _res = os.popen('git pull').read()
            if 'Fast-forward' in _res:
                con.set('local','need_stop','1')
            else:
                con.set('local','need_stop','0')
            con.write(open(local_path,'w+'))
        if con.get('local','need_restart') == '1' or _f:
            _f = False
            p = Process(target=fun,args=args,kwargs=kwargs)
            p.start()
            con.set('local', 'need_restart','0')
            con.write(open(local_path,'w+'))
        time.sleep(10)

def check_stop_flag():
    """
    检测是否应该中止,在被托管的进程里使用
    """
    con = ConfigParser()
    con.read_file(codecs.open(local_path,'r+','utf-8-sig'))
    if con.get('local','need_stop') == "1":
        print('code was updata,now stop running!!')
        con.set('local','need_stop',"0")
        con.set('local','need_restart',"1")
        con.write(open(local_path,"w+"))
        exit(0)

测试main.py文件函数

#-*-coding:utf-8-*-
from auto import check_stop_flag,auto_manager_main,set_code_check_time
import time
def run(x=0,y=0):
    #开始子进程
    print('run!!!!')
    for i in range(x,500):
        #设置在这里检测是否要退出进程
        check_stop_flag()
        #....作不该该忽然中断任务....
        time.sleep(1)
        print('i={} y={}'.format(i,y))
        #....完成了...

def tx(y=1):#(稍后测试我把1改为10)
    #main函数【可变参数能够传这里,若是参数值改变,程序重启后会跟随改变】
    run(x=1,y=y)#(稍后测试我把1改为10)
    
if __name__ == '__main__':
    #设置检测频率(彷佛并不会生效,待验证优化)
    set_code_check_time(1)
    #把进程委托自动管理【固定参数能够这里传入,重启程序参数也不会跟随改变的】
    auto_manager_main(tx,y=1)#(稍后测试我把1改为10)

我先运行main.py文件,顺利的执行后,我在git上把参数x和y的值由1改为10。结果以下。工具

主进程PID: 6004
run!!!!
i=1 y=1
i=2 y=1
i=3 y=1
i=4 y=1
i=5 y=1
i=6 y=1
i=7 y=1
i=8 y=1
i=9 y=1
i=10 y=1
i=11 y=1
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
i=12 y=1g objects:  33% (1/3)
Unpacking objects: 100% (3/3), done.
From gitee.com:kid0/tx
   3ca10d8..9f08a5d  master     -> origin/master
i=13 y=1
code was updata,now stop running!!
run!!!!
i=10 y=1
i=11 y=1
i=12 y=1
i=13 y=1
i=14 y=1

在我git改了代码后,main正常的本身退出,而且重启了。参数也是用最新的去运行。测试

实验完成!!!投入使用!优化

注意:

一、.gitignore文件必须加入忽略local.txt文件!!!不然会致使冲突,没法下拉代码!!!

二、可能会被修改的参数绝对不能auto_manager_main传!应当用另外一个函数简单包起main函数,像我测试的那样。

解疑:

一、为何用Process(进程)而不是threading(线程)?

python虽然是解释语言,但它须要把py编译成pyc文件去运行。进程启动时会从新编译,但线程不会。你们能够试试。虽然会更新代码并重启,可是运行结果不会改变。

二、是否适用于全部python项目?

适用于“一套代码放在多个客户机,而且常常更新git”的状况。对于server服务我并不推荐。由于server服务应该是累积必定的更新后再更新到线上。

三、直接杀掉进程用脚本启动会不会更简单?

条条大路通罗马。方法不少,看你喜欢。像个人项目,任务是从队列拿的。若是忽然干掉了进程,任务就会丢失,并且我这每一个任务都十分关键!条条任务都是钱!(我拿到任务会写到本地文件内,完成再删除,防机器宕机的可能)若是是普通爬虫之类的倒无所谓,丢失1-2条数据不要紧的。

四、git pull为何不是检测“Already up to date”?

一开始我也是这样的考虑的。可是,网络异常、冲突、sshkeygen失效等问题都会致使无限的重启程序。所以只能检测pull成功下拉的标识。

五、为何在上述案例中x的值改了,y没有改?

父进程是守护进程,负责更新代码和启动main,参数y是父进程给的,父进程并无重启,因此y没有改变。x是子进程从新编译后才给的参数,因此是最新的。

(ps:设置检测频率是否生效我没去测,不过10秒或者60秒的检测频率已经足够的了)

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

以上就是我开发的模块和理解。欢迎你们使用和改进。

转载请注明出处。https://my.oschina.net/jacky326/blog/3027504

相关文章
相关标签/搜索