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

相關文章
相關標籤/搜索