一.引言
工程实践中,经常遇到任务故障或其他原因导致任务执行失败,常见的方法是设计 Cron Protect 脚本监控任务执行,但是如果任务执行超时但不退出 Cron Protect 则不会生效,这时候需要强制 Kill 掉任务并重启,但是每次都需要登录服务器,非常的麻烦,这时候可以通过设计接口 + 监听程序,实现程序的自动化启动,只需手机访问接口即可。
二.实践
经过上面的分析,该监控的功能主要涉及到监控接口参数和实现启动任务,这里需要下述3个工具:
=> 监听状态: Redis
实时监控接口传入的最新值,这里采用 Redis 队列实现
=> 接口:
接口通过 Python 的 FastAPI 简洁实现
=> 启动任务:
Python 启动 sh 任务可以通过 SubProcess 实现
1.监听状态 + 启动任务
由于 Redis 监听状态与重启任务是两个连续的步骤,即监听到启动状态随后执行启动任务操作,所以这两个放到一起实现,当然不使用 Redis 也可以,可以使用任意的存储端实现对状态值的传递。
#coding=utf-8
import redis
import subprocess
import datetime
import time
# 初始化客户端
r = redis.Redis(host='your_host', port='your_port', decode_responses=True)
# 其他管道
# client = new MyClient(host, port)
# 队列 Key
read_key = 'value_state'
def getValue():
now = datetime.datetime.now()
length = r.llen(read_key)
# 只保留最新 并清空队列
r.ltrim(read_key,0,0)
value = r.rpop(read_key)
curLength = r.llen(read_key)
print("time:%s value: %s oriLength:%s curLength:%s" % (now, value, length, curLength))
if value == "self_defined":
log = subprocess.Popen("nohup sh test.sh > log 2>&1 &", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
print("Application Started At:", now, log.communicate()[0].strip())
while(1):
getValue()
time.sleep(10)
A.getValue() 函数负责从 Redis 队列中获取最新的值并清除当前队列中多余的值,所以执行了 r.ltrim 操作,这样避免接口异常传入过多状态值而导致任务多次重启
B.rpop 返回最新元素,根据元素的值与自定义的值可以决定是否 subprocess.Popen 吊起自己的任务,这里 Popen 是异步执行,所以不会导致 python 程序同步等待,如果需要监听执行任务的状态,则可以修改 nohup 的提交方式,这样 log.communicate() 会堵塞操作等待 test.sh 执行完毕并判断任务执行状态
C.通过 While True 实现监听系统的 7x24 服务,这里 sleep 设置每次监听的 interval
2.接口
python 实现简单接口可以通过 FastAPI,方便高效,接口只需要实现一个基本 Get 功能即可,通过手机移动端就可以把参数传给 Redis,从而监听程序获取最新状态值
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from fastapi import FastAPI
from redis import Redis
send = Redis(host='your_host', port='your_port')
app = FastAPI()
@app.get("/monitor/{value}")
async def send_info(value: str = None):
send.lpush("value_state", value)
return {"value": value}
可以通过 uvicorn 部署到自己的服务器上,也可以使用 Netstat 部署 ,reload 代表更新代码随时更新该 APP
# uvicorn Monitor:app --reload
可以直接通过 URL 传参:
http://127.0.0.1:8000/monitor/self_difined
也可以进入交互界面传参:
http://127.0.0.1:8000/docs
3.测试
先构建一个测试脚本 test.sh:
#!/bin/bash
echo `date` 任务开始...
然后 nohup 挂起 python 程序并在服务器部署接口就可以手机端控制任务执行了,任务每隔 10 s进行一次监控,可以查看 log 日志看到 test.sh 的日志:
Thu Sep 16 10:21:04 CST 2021 任务开始...
10:21:04 与我们接口日志的 Application Start 时间吻合,执行重启任务后队列清空,持续监控
后续需要重启任务不再需要登录服务器,只需登录手机访问:
http://127.0.0.1:8000/monitor/self_difined 即可完成随时唤醒任务,非常的奈斯