flowchart TD
A[启动 ProxyPool.run] --> B[get_Redis_vps_info 从 Redis hash vps_info 读取 VPS 清单]
B --> C[creat_hosts:每条清单创建 Host,并在构造时尝试 SSH]
C --> D{DEBUG?}
D -- true --> E[串行 reconnect + update_proxy,方便本地调试]
D -- false --> F[进入 while True 循环,用 deque 轮询 Host]
F --> G[pop 一台 Host,先 reconnect,避免旧 SSH 断开]
G --> H[启动 Thread(target=host.update_proxy),主循环把 Host appendleft 放回队列]
H --> I[Host.update_proxy 先检查 restricted_proxy set]
I -- 命中限制名单 --> I1[暂停更新;保护被封禁或异常节点]
I -- 未限制 --> J[读取 Redis proxy_pool 里的 old_proxy_ip/time,并 hdel 当前态]
J --> K[_update_proxy:SSH 执行 pppoe-stop/start,ifconfig 解析 ppp IP]
K --> L{重拨结果}
L -- 成功 --> M[CurrRequest.proxy_test 用 aiohttp 并发 10 个请求测试代理]
M --> M1[score=成功次数;delay=成功请求平均耗时,失败全量时 delay=5]
L -- 停止失败 --> N[message=停止拨号失败;仍对当前 IP 测速,保留可用性判断]
L -- 异常 --> O[message=重新拨号失败;ssh=None,下次 reconnect 重建连接]
L -- VPS ping 失败 --> P[status=networkError,说明远端出网问题]
M1 --> Q{proxy_ip 存在且与 old_proxy_ip 不同?}
N --> Q
O --> Q
P --> Q
Q -- 是 --> R[zadd proxy_catch:addr|proxy_ip|score|delay|ts,按时间戳记录换 IP 历史]
Q -- 否 --> S[只记录 update fail;避免相同 IP 被当成新代理]
R --> T[post_proxy 上报 adm.ishuyun.com/webapi/proxy_report,最多尝试 3 次]
S --> T
T --> U[hset proxy_pool 写当前态:ip/port/proxy_ip/time/score/delay/status/message/region]
U --> F