系列定位:让"写一个能稳定跑半年的量化脚本"这件事,从散落的经验贴变成可复制的流水线。
痛点:脚本能跑了,但离开电脑就停
上一篇我们给脚本加上了定时调度。现在它能每天自动执行数据拉取和归档,看起来万事大吉。
但还有一个隐藏风险:运行环境不稳定。
- 笔记本合盖休眠 → Python 进程被系统挂起
- SSH 窗口关闭 →
nohup也保不住某些场景 - 云服务器重启 → 任务彻底消失,要手动登录重新启动
- 脚本偶发异常崩溃 → 没人知道它停了,直到发现数据断更
定时调度解决的是"什么时候跑",后台守护解决的是"跑了之后怎么一直活着"。
本文你将得到什么
- 为什么
nohup和screen不是生产级方案 - 用 Python 模拟守护进程:主进程监控 + 子进程崩溃自动重启(跨平台演示)
- Linux 生产环境标准方案:systemd unit 配置详解
- 日志查看与排错:
journalctl常用命令
先做一个跨平台演示:Python 进程守护
在深入 systemd 之前,先用一段纯 Python 代码理解"守护"的本质:
一个进程(daemon)持续监控另一个进程(worker),发现 worker 挂了立刻重新启动。
python
#!/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
核心逻辑只有三行:
subprocess.Popen()启动 workerworker_proc.poll()检查是否还在运行- 如果退出了,回到第 1 步重新启动
这就是所有进程守护的本质------包括 systemd。
生产环境方案:systemd(Linux)
上面的 Python 模拟只在"理解原理"时有用。生产环境不需要自己造轮子,Linux 的 systemd 已经提供了完整、健壮的进程管理能力。
1. 创建 systemd unit 文件
/etc/systemd/system/quant-data.service:
ini
[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
2. 关键配置项解释
| 配置项 | 作用 |
|---|---|
Type=simple |
前台运行(Python 脚本无需 daemon 化) |
Restart=always |
无论退出码是什么,都自动重启 |
Restart=on-failure |
仅异常退出(非零码)时重启 |
RestartSec=5 |
崩溃后等待 5 秒再重启,避免刷爆 CPU |
Environment= |
注入环境变量,证书不用写进代码 |
量化场景推荐
Restart=on-failure。如果脚本正常退出(比如跑完了当日全部任务),不需要强制重启;只有异常崩溃时才重启。
3. 启动与查看状态
bash
# 重载配置
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:
bash
pip install mairui
证书获取:访问麦蕊官网申请免费版或付费版 API 证书。
免责声明:本文仅供技术学习交流,不构成任何投资建议。股市有风险,入市需谨慎。