【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起

系列定位:让"写一个能稳定跑半年的量化脚本"这件事,从散落的经验贴变成可复制的流水线。


痛点:脚本能跑了,但离开电脑就停

上一篇我们给脚本加上了定时调度。现在它能每天自动执行数据拉取和归档,看起来万事大吉。

但还有一个隐藏风险:运行环境不稳定。

  • 笔记本合盖休眠 → Python 进程被系统挂起
  • SSH 窗口关闭 → nohup 也保不住某些场景
  • 云服务器重启 → 任务彻底消失,要手动登录重新启动
  • 脚本偶发异常崩溃 → 没人知道它停了,直到发现数据断更

定时调度解决的是"什么时候跑",后台守护解决的是"跑了之后怎么一直活着"。


本文你将得到什么

  1. 为什么 nohup 和 screen 不是生产级方案
  2. 用 Python 模拟守护进程:主进程监控 + 子进程崩溃自动重启(跨平台演示)
  3. Linux 生产环境标准方案:systemd unit 配置详解
  4. 日志查看与排错:journalctl 常用命令

先做一个跨平台演示:Python 进程守护

在深入 systemd 之前,先用一段纯 Python 代码理解"守护"的本质:

一个进程(daemon)持续监控另一个进程(worker),发现 worker 挂了立刻重新启动。

!/usr/bin/env python3

-- coding: utf-8 --

"""
进程守护 demo:主进程监控 worker,异常退出时自动重启
"""
import os
import sys
import time
import subprocess
from datetime import datetime

def now():
return datetime.now().strftime("%H:%M:%S")

def worker():
"""模拟工作进程:执行量化任务,12 秒后模拟异常退出"""
pid = os.getpid()
print(f"[{now()}] [worker pid={pid}] 启动,开始执行任务...")
time.sleep(12)
print(f"[{now()}] [worker pid={pid}] 模拟异常崩溃!")
sys.exit(1)

def daemon(duration_sec=35):
"""守护进程:持续监控 worker,发现退出立即重启"""
print(f"[{now()}] [daemon] 启动,策略:worker 异常退出 -> 立即重启")
start = time.time()
worker_proc = None
restart_count = 0

while time.time() - start < duration_sec:
if worker_proc is None or worker_proc.poll() is not None:
if worker_proc is not None:
rc = worker_proc.returncode
print(f"[{now()}] [daemon] 检测到 worker 退出 (rc={rc}),执行第 {restart_count + 1} 次重启...")
worker_proc = subprocess.Popen([sys.executable, file, "--worker"])
restart_count += 1
print(f"[{now()}] [daemon] worker 已重启,新 pid={worker_proc.pid}")
time.sleep(1)

清理

if worker_proc and worker_proc.poll() is None:
worker_proc.terminate()
worker_proc.wait(timeout=3)
print(f"[{now()}] [daemon] 演示结束。期间 worker 共启动 {restart_count} 次")

if name == "main":
if "--worker" in sys.argv:
worker()
else:
daemon(duration_sec=35)

运行效果:

[10:27:07] [daemon] 启动,策略:worker 异常退出 -> 立即重启
[10:27:07] [daemon] worker 已重启,新 pid=26988
[10:27:19] [worker pid=26988] 模拟异常崩溃!
[10:27:20] [daemon] 检测到 worker 退出 (rc=1),执行第 2 次重启...
[10:27:20] [daemon] worker 已重启,新 pid=32628

核心逻辑只有三行:

  1. subprocess.Popen() 启动 worker
  2. worker_proc.poll() 检查是否还在运行
  3. 如果退出了,回到第 1 步重新启动

这就是所有进程守护的本质——包括 systemd。


生产环境方案:systemd(Linux)

上面的 Python 模拟只在"理解原理"时有用。生产环境不需要自己造轮子,Linux 的 systemd 已经提供了完整、健壮的进程管理能力。

  1. 创建 systemd unit 文件

/etc/systemd/system/quant-data.service:

[Unit]
Description=量化数据采集服务
After=network.target

[Service]
Type=simple
User=quant
WorkingDirectory=/home/quant/app
Environment=MAIRUI_LICENCE=LICENCE-66D8-9F96-0C7F0FBCD073
ExecStart=/home/quant/venv/bin/python /home/quant/app/run.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

  1. 关键配置项解释

配置项 作用
Type=simple 前台运行(Python 脚本无需 daemon 化)
Restart=always 无论退出码是什么,都自动重启
Restart=on-failure 仅异常退出(非零码)时重启
RestartSec=5 崩溃后等待 5 秒再重启,避免刷爆 CPU
Environment= 注入环境变量,证书不用写进代码

量化场景推荐 Restart=on-failure。如果脚本正常退出(比如跑完了当日全部任务),不需要强制重启;只有异常崩溃时才重启。

  1. 启动与查看状态

    重载配置

    sudo systemctl daemon-reload

    开机自启 + 立即启动

    sudo systemctl enable --now quant-data

    查看运行状态

    sudo systemctl status quant-data

    实时查看日志

    sudo journalctl -u quant-data -f

    查看今日全部日志

    sudo journalctl -u quant-data --since today


Windows 用户怎么办?

如果你的开发机是 Windows,有两条路径:

路径 A:继续开发调试

  • 用上面的 Python daemon() 演示方案临时守护
  • 或写一个简单的 .bat 脚本放在"启动文件夹"

路径 B:部署到 Linux 服务器

  • 量化脚本最终还是要 7×24 运行,笔记本不是长久之计
  • 一台最低配云服务器(2核2G)足够跑个人量化任务
  • 部署后用 systemd 管理,配合 cron 做定时调度

推荐:开发在 Windows,部署用 Linux + systemd。


常见坑

坑 现象 解决
Restart=always 把正常退出也重启 脚本执行完当日任务后正常退出,systemd 又把它拉起来 改用 Restart=on-failure,或在脚本末尾循环等待而不是直接退出
环境变量没传进去 脚本读不到 MAIRUI_LICENCE 写在 [Service] 的 Environment= 里,不要用 ~/.bashrc
日志找不到 不知道脚本输出了什么 用 journalctl -u quant-data -f 实时查看
权限不足 systemctl start 失败 检查 User= 是否有权限访问工作目录和 Python 环境
虚拟环境路径不对 ImportError ExecStart 写虚拟环境的完整 python 路径,如 /home/quant/venv/bin/python


小结

  • 守护的本质:一个进程监控另一个进程,死了就重启
  • 开发调试:上面的 Python daemon() 代码足够理解原理
  • Linux 生产环境:systemd 是标准答案,Restart=on-failure + journalctl 排错
  • Windows:建议最终部署到 Linux 服务器,本地仅做开发

下篇预告:脚本稳定跑了,但日志文件越写越大、出错时大海捞针怎么办?#09 日志轮转与结构化日志,让排错不再头疼。


代码与文档

本文配套代码已开源在 GitHub:https://github.com/MaiRuiApi

安装 SDK:

pip install mairui

证书获取:访问麦蕊官网申请免费版或付费版 API 证书。


免责声明:本文仅供技术学习交流,不构成任何投资建议。股市有风险,入市需谨慎。

posted @ 2026-09-18 16:08  量化分析码农  阅读(13)  评论(0)    收藏  举报