Dew-OF-Aurora 2 týždňov pred
rodič
commit
bd94b2646b
3 zmenil súbory, kde vykonal 50 pridanie a 4 odobranie
  1. 43 3
      README.md
  2. 4 0
      config.server.json
  3. 3 1
      workflow.md

+ 43 - 3
README.md

@@ -95,7 +95,12 @@ GIT_FORCE_COMMIT=1 bash scripts/run_update_and_commit.sh config.server.json
 | 参数选项 | 默认值 | 说明 |
 | :--- | :--- | :--- |
 | `--config <path>` | `config.server.json` | 配置文件路径(若为相对路径,则相对于仓库根目录) |
-| `--interval <value>` | `30min` | 定时器执行间隔,例如 `1h`、`30min`、`10s` 等 |
+| `--interval <value>` | `30min` | `--offpeak-interval` 的别名(定时器默认/非高峰间隔) |
+| `--peak-start <hour>` | `19` | 高峰时段的起始小时数,取值范围 `0-23`(如 19 代表 19:00) |
+| `--peak-end <hour>` | `24` | 高峰时段的截止小时数,取值范围 `1-24`(如 24 代表 24:00,均会被自动规范化为 0) |
+| `--peak-tz <timezone>` | `Asia/Shanghai` | 高峰时段判定的参考时区 |
+| `--peak-interval <value>` | `10min` | 高峰时段的域名更新间隔,如 `5min`、`10m` |
+| `--offpeak-interval <value>`| `30min` | 非高峰时段的域名更新间隔,如 `30min`、`1h` |
 | `--user <name>` | 当前 `sudo` 用户 | 运行 systemd 服务的非 root 系统用户 |
 | `--group <name>` | 当前 `sudo` 用户组 | 运行 systemd 服务的系统用户组 |
 | `--git-push <0\|1>` | `1` | 选出新域名并 commit 后,是否自动推送(`git push`)到远程仓库 |
@@ -171,10 +176,13 @@ sudo systemctl status vmess-domain-rotator.service
 # 手动立即触发一次更新(无需等待定时器,方便测试)
 sudo systemctl start vmess-domain-rotator.service
 
-# 实时查看运行日志
+# 实时查看运行日志(包含定时任务与手动执行日志,推荐)
+sudo journalctl -t vmess-domain-rotator -f --no-pager
+
+# 仅查看定时任务服务的运行日志
 sudo journalctl -u vmess-domain-rotator.service -f --no-pager
 
-# 查看最近 100 行日志
+# 查看服务最近 100 行日志
 sudo journalctl -u vmess-domain-rotator.service -n 100 --no-pager
 
 # 语法与配置预检
@@ -244,6 +252,38 @@ chore(fallback): rotate preferred value to example.com (2026-05-11T13:03:16Z)
 
 `chore(fallback)` 表示源端出错、使用了上次的可用值。
 
+#### 3.7.1 手动执行日志重定向 (journald tee)
+当你在控制台手动执行 `scripts/run_update_and_commit.sh`(非 systemd 服务直接运行)时,为了确保调试时的所见所得与运维的日志可追溯性,脚本内置了 `journald tee` 日志重定向功能:
+- 脚本检测到环境变量 `INVOCATION_ID` 为空且系统安装有 `systemd-cat` 时,会自动通过管道进行双流输出重定向。
+- **所见即所得**:终端内仍会显示常规的标准输出(stdout)与标准错误(stderr),方便交互式调试与结果观测。
+- **系统级追溯**:输出的副本会被自动发送给 systemd-journald 守护进程,并打上 `vmess-domain-rotator` 的 Syslog Identifier 标签。
+- 可以使用 `journalctl -t vmess-domain-rotator -f` 命令将定时任务与手动调试的日志归于同一时间线混合排查。
+
+---
+
+### 3.8 高峰期/非高峰期双频自适应调度策略
+项目提供了非常灵活的**高峰期(Peak Hour)与非高峰期(Off-Peak Hour)双频自适应调度**机制。此设计能够使系统在晚高峰期间高频运行测速或更新以保证代理域名的实时可用,并在低谷期间自动降低频率以降低对第三方 API 及网络资源的开销。
+
+#### 3.8.1 定时器最小周期驱动
+- `install_debian.sh` 安装脚本在部署时,会自动读取 `--peak-interval`(高峰间隔,默认 `10min`)与 `--offpeak-interval`(非高峰间隔,默认 `30min`)。
+- 脚本通过 `to_minutes` 函数将其统一解析为分钟数,并取两者的**最小值**(通常为高峰期的时间间隔)作为 systemd timer 定时的基础触发周期:
+  $$\text{TIMER\_INTERVAL} = \min(\text{Peak Interval}, \text{Off-Peak Interval})$$
+- 也就是说,系统底层的定时器会以最高频的节奏(如每 10 分钟一次)醒来并启动 `run_update_and_commit.sh` 脚本。
+
+#### 3.8.2 脚本自适应判定与容差跳过
+每次脚本被唤醒时,会判断当前时间是否处于高峰期:
+1. **时区一致性**:通过 `TZ="Asia/Shanghai" date` (时区可配置)跨命令强制时区覆盖,即便服务器处于 UTC 时区或海外机房,也能精准在北京时间高峰段(默认 19:00 - 24:00)运行。
+2. **跨零点支持**:判断支持跨越午夜的区间定义(例如 `peak_start=22, peak_end=2` 代表晚上十点到凌晨两点)。
+3. **高峰期行为**:如果属于高峰期,直接放行,每次触发均会完整执行后续的 Python 优选与 Git 同步(10 分钟更新一次)。
+4. **非高峰期判定(容差对齐)**:
+   如果属于非高峰时段,脚本只应在长周期边界(如 30 分钟边界,即 `0` 分或 `30` 分)执行更新。
+   为了防止由于系统调度微小漂移(例如定时器在 `29m 58s` 或 `30m 02s` 唤醒脚本)导致漏判,脚本设计了**容差窗口(Tolerance Window)判定**:
+   - 容差窗口大小定为高峰周期的二分之一左右:
+     $$\text{Tolerance} = \frac{\text{Peak Interval} + 1}{2}$$
+   - 脚本计算当前分钟数对非高峰间隔的余数:
+     $$\text{Remainder} = \text{Current Minute} \pmod{\text{Off-Peak Interval}}$$
+   - 如果余数超出容差区间,代表这是一次中间的冗余唤醒(如第 10 分钟或第 20 分钟),脚本将记录 `off-peak run skipped` 日志并**安全退出 0**;否则(如第 29 分钟或第 0 分钟)进行放行(30 分钟更新一次)。
+
 ---
 
 ## 4. 本地 Python `cfst` 模式

+ 4 - 0
config.server.json

@@ -74,6 +74,10 @@
       {
         "field": "yd_pkg_lost_rate",
         "weight": 10.0
+      },
+      {
+        "field": "yd_score",
+        "weight": 5.0
       }
     ],
     "prefer_lower": true,

+ 3 - 1
workflow.md

@@ -24,7 +24,9 @@ flowchart TD
       B13 --> B14[write runtime/state.json]
     end
 
-    A2 --> C1[resolve configured output paths]
+    A2 --> C0{force-commit=1 OR<br/>in peak OR<br/>on offpeak boundary?}
+    C0 -- no --> CS[skip run and exit 0]
+    C0 -- yes --> C1[resolve configured output paths]
     C1 --> A4
     A4 --> C2[capture updater JSON output]
     C2 --> C3[detect status: error_use_last_good?]