feat(vps-xray): 生成 timer/service/guard 三个单元文件
timer 每天唤醒,N 天间隔判断交给 guard 脚本, 绕开 OnCalendar 无法表达任意 N 天间隔的限制。
This commit is contained in:
@@ -148,6 +148,85 @@ update_env_field() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# 生成 timer / service / guard 三个文件。
|
||||
# 完整部署与 --restart 共用本函数,避免两条路径各写一份实现后漂移。
|
||||
render_restart_units() {
|
||||
local days="$1" time="$2" tz="$3"
|
||||
|
||||
mkdir -p "$SYSTEMD_DIR" "$(dirname "$GUARD_BIN")"
|
||||
|
||||
# 守卫脚本:systemd 的 OnCalendar 表达不了「每 N 天」——
|
||||
# *-*-1/7 是「每月 1/8/15/22/29 号」,跨月会重置成 2~3 天。
|
||||
# 所以 timer 只负责每天到点唤醒,间隔判断放到这里。
|
||||
cat > "$GUARD_BIN" << EOF
|
||||
#!/bin/bash
|
||||
# 由 deploy.sh 生成,请勿手工编辑
|
||||
STATE="${RESTART_STATE_FILE}"
|
||||
DAYS=${days}
|
||||
|
||||
now=\$(date +%s)
|
||||
last=0
|
||||
if [ -f "\$STATE" ]; then
|
||||
last=\$(cat "\$STATE" 2>/dev/null || echo 0)
|
||||
# 内容被写坏时按 0 处理,即允许立即重启
|
||||
[[ "\$last" =~ ^[0-9]+\$ ]] || last=0
|
||||
fi
|
||||
|
||||
# 300 秒容差:systemd timer 默认 AccuracySec=1min,第 N 次触发的实际间隔
|
||||
# 可能是 N*86400-30s。严格比较会判「不满」从而顺延整整一天,且误差会累积。
|
||||
if [ "\$last" -gt 0 ] && [ \$(( now - last )) -lt \$(( DAYS * 86400 - 300 )) ]; then
|
||||
echo "距上次重启不足 \${DAYS} 天(已过 \$(( (now - last) / 86400 )) 天),跳过"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "\$(dirname "\$STATE")"
|
||||
# 必须先写时间戳:restart 会中断本脚本所在的 systemd 事务,
|
||||
# 顺序反了会丢记录,退化成每天都重启。
|
||||
# 代价是重启失败时本轮仍被记为已执行——这比陷入每日重启循环可接受。
|
||||
echo "\$now" > "\$STATE"
|
||||
echo "距上次重启已满 \${DAYS} 天,执行重启"
|
||||
exec systemctl restart xray
|
||||
EOF
|
||||
chmod 755 "$GUARD_BIN"
|
||||
|
||||
cat > "${SYSTEMD_DIR}/xray-restart.service" << EOF
|
||||
[Unit]
|
||||
Description=Scheduled restart of Xray (every ${days} day(s))
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
Environment=PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
||||
ExecStart=${GUARD_BIN}
|
||||
EOF
|
||||
|
||||
cat > "${SYSTEMD_DIR}/xray-restart.timer" << EOF
|
||||
[Unit]
|
||||
Description=Wake xray-restart daily at ${time} ${tz}; the guard enforces the ${days}-day interval
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* ${time}:00
|
||||
TimeZone=${tz}
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
}
|
||||
|
||||
# 删除 timer / service / guard。状态文件刻意保留:
|
||||
# 以后重新启用时,距上次已超 N 天则首次触发即重启,符合直觉。
|
||||
remove_restart_units() {
|
||||
if [ ! -f "${SYSTEMD_DIR}/xray-restart.timer" ] && [ ! -f "$GUARD_BIN" ]; then
|
||||
return 1
|
||||
fi
|
||||
systemctl disable --now xray-restart.timer >/dev/null 2>&1 || true
|
||||
rm -f "${SYSTEMD_DIR}/xray-restart.timer" \
|
||||
"${SYSTEMD_DIR}/xray-restart.service" \
|
||||
"$GUARD_BIN"
|
||||
return 0
|
||||
}
|
||||
|
||||
resolve_restart_config || exit 1
|
||||
|
||||
# 过渡兼容:harden_system / start_service / save_env 仍引用 DAILY_RESTART,
|
||||
|
||||
Reference in New Issue
Block a user