由于celery最小只能到分钟级别,但是日常有需要每隔10秒同步一遍获取远程系统能力
python3""" Auto reload celery runner script Usage: python manage.py sync_perms See: https://stackoverflow.com/a/49166246/2544762 """ import signal import traceback from datetime import datetime from logging import getLogger from time import sleep from typing import Dict from django.apps import apps from django.conf import settings from django.core.management.base import BaseCommand from mobile.tasks import job_watch_sonic_devices logger = getLogger(__name__) class Command(BaseCommand): def handle(self, *args, **options): # 退出标记 flag_terminate = False # 退出信号处理(Ctrl + C),使得可以正常结束不用 kill def signal_handler(signal, frame): nonlocal flag_terminate flag_terminate = True signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # 死循环轮询定时任务 while not flag_terminate: logger.info(f'定时任务开始执行:{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') try: job_watch_sonic_devices() except Exception as e: print(f'watch sonic e: {e}') traceback.print_exception(e) # 整体执行时间需要2秒,这里设置8秒,基本10秒内一个轮回 sleep(8)
python3signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler)
捕获 Ctrl + C (SIGINT) 和 终止信号 (SIGTERM)。
使用 nonlocal flag_terminate 让信号处理函数能修改外部变量,确保可以优雅退出循环,而不是被强制 kill。
优点:
运行中按 Ctrl+C 可以安全结束(会在下个循环退出)。
避免直接 kill -9 导致状态不一致。
python3flag_terminate = False def signal_handler(signal, frame): nonlocal flag_terminate flag_terminate = True
当用户 Ctrl+C(SIGINT)或 kill(SIGTERM)时,不是立刻杀掉进程,而是执行 signal_handler:
把 flag_terminate 设成 True。
主循环每轮都会检查 flag_terminate:
如果 True,退出循环,任务结束前可以优雅清理(比如保存状态、断开连接)。
这样:
正在执行的那一轮任务会先跑完。
然后在下一轮循环检查到退出标志,再干净地退出。
信号处理就是给死循环任务加了一个“安全刹车”,让你按下 Ctrl+C 时,不是直接翻车,而是慢慢停下来。
如果只看 Python 解释器层面,当收到信号时,信号处理函数(signal_handler)的执行是同步的。
解释器会在执行字节码的“安全点”检测是否有挂起的信号:
如果有,就暂停当前的 Python 代码执行;
同步调用你注册的 signal.signal(...) 处理函数;
处理函数执行完后,回到原来的位置继续执行
本文作者:lixf6
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!