优雅的repo sync自动重试
while [[ 1 ]]; do # 用ifstat检测网速 speed=`ifstat 1 1 | tail -n 1 | awk '{print $1}'` result=$(echo "$speed < $min_speed" | bc) if [[ $result == "1" ]]; then ((counter++)) else ((counter=0)) fi if ((counter > retry_delay)); then ((counter=0)) echo "netspeed low. restart!" ((n_retries++)) restart_sync fidoneecho "completed with $n_retries retries"
在上面这个版本中, 我们使用ifstat来检测网速, 没秒检测一次, 如果持续一段时间没流量, 就kill掉所有repo进程. 这里有个问题: 如果repo sync正常退出了, 那么也就没有流量了, 所以这个脚本会无限执行, 永远不会停止. 同时, 我们需要知道repo退出时, 是成功的退出, 还是出错退出? 要检测返回值就必须用wait, 然而wait会使主进程 block住, 主进程就无法再去检测了. 为了解决这个问题, 可以使用bash coproc
Bash Coproc
简单的说bash coproc就是创建一个子进程, 并可以取到子进程的一些信息, 可以和子进程通信. 这里我们需要的是子进程的pid信息, 只要有了这个, 我们就可以在不用wait的情况下知道子进程是否还活着, 如果已经退出了, 我们再用wait去取它的返回值就可以了. 创建coproc的语法如下:
coproc <name> command 其中为你给他起的名字(可选), command为子进程运行的命令. 运行完后, 可以在$name_PID中取到子进程的PID. # 第二个版本有了coproc, 我们可以写出第二个版本:
#!/bin/bash# 当前 repo sync 进程的 pidPID=kill_prog() { # kill 当前repo sync子进程 echo "kill : $PID" [[ -n $PID ]] && kill $PID}start_sync() { # 启动子进程(使用coproc) coproc syncproc { repo sync; } PID=$syncproc_PID}restart_sync() { kill_prog start_sync}# 如果网络流量在retry_delay时间内小于min_speed, 则认为repo sync已经卡住了min_speed="50"retry_delay=300((counter=0))((n_retries=0))restart_syncwhile [[ 1 ]]; do # 用ifstat检测网速 speed=`ifstat 1 1 | tail -n 1 | awk '{print $1}'` result=$(echo "$speed < $min_speed" | bc) if [[ $result == "1" ]]; then ((counter++)) else ((counter=0)) fi if [[ `ps -p $PID| wc -l` == "1" ]]; then # 检测到子进程已经退出(ps已经查不到它了) # 用wait取得子进程返回值 wait $PID if [[ $? -eq 0 ]]; then echo "sync successful" break else echo "sync failed" ((counter=0)) ((n_retries++)) restart_sync continue fi fi if ((counter > retry_delay)); then ((counter=0)) echo "netspeed low. restart!" ((n_retries++)) restart_sync fidoneecho "completed with $n_retries retries"在这个版本里, 我们知道子进程的pid, 可以有针对性的kill, 并且在子进程正常退出时, 也能检测到, 并及时退出程序.好了, 现在终于可以自动sync代码了, 下篇就开始写关于android的blog:-)