 q792602257andClaude Opus 5
|
3284e086ad
|
feat(trading): 浏览器掉线兜底——任务边界自愈重建,中途掉线转 needs_human
SiteInteractor 的 Chromium 是进程级单例,此前启动后即假定永远活着:全仓唯一的
is_connected() 探活在 scraping 侧,交易侧既不探活也不重启。容器里 Chromium 崩溃
是有真实前提的(/dev/shm 不足、OOM kill、seccomp 挡 sandbox,docker-compose.yml
里已有相关注释),一旦发生,进程还活着但之后每一单都会失败,且 /health 恒返回
ok,restart: unless-stopped 永远不会被触发。
更隐蔽的一条:clear_cart / enter_checkout / pay 等处的 new_page()、context.request
写在 try 之外,掉线抛的 TargetClosedError 不是 AppError,会穿过 runner 的
except AppError 落到主循环那个只记日志的兜底里——任务一次都不上报,网关侧要干等
整个 lease_ttl(默认 300s)才被 sweep 置 stale。clear_cart 是 execute() 的 step 0,
浏览器死时最先撞上的正是它。
分三层处理:
- 任务边界自愈。_launch() 从 start() 抽出,_context_options() 统一 context 参数
(重建必须与启动完全一致,指纹漂移就是一次风控事件);_refresh_context_if_stale
改名 _ensure_context_ready(),先探活重建再做原有的 storage_state mtime 检查
(顺序不可换,mtime 重建要用 self._browser)。重建前丢弃 _checkout_pages 里的
残留确认页并记 warning——那些 Page 已随浏览器一起没了。
- 中途掉线不重建,抛 BrowserDeadError(新增,5006)。新增 _new_page() 与
_request() 两个壳收口裸异常;_request() 只在确认浏览器真死了时才改写异常,
站点 5xx 这类正常业务失败原样抛出。submit_order / pay 入口用
_require_live_browser() 直接拒绝:这两步复用 enter_checkout 留存的 Page,
重建救不回服务端订单草稿,而 pay 跑的时候订单已经真的提交了。顺带修掉一个
误诊——浏览器死时 submit_order 原先报「未找到确认按钮」,把「浏览器崩了」
说成「站点改版了」,两者的处置方式完全不同。
- runner 把 BrowserDeadError 转 needs_human 而非 failed,except 分支排在
except AppError 之前(子类,顺序反了就报 failed)。掉线发生在动作中途,
站点侧生效与否无从判断,不能给上游「明确失败」的结论。
/health 暴露 browser 状态,掉线时 degraded + HTTP 503 + code 5006,让
Dockerfile.trading 的 HEALTHCHECK 探到并重启容器。重启不会导致重复下单:网关侧
任务绝不自动重投,租约过期只置 stale 等人工 reclaim(docs/order-gateway.md §5),
重启只是恢复领新任务的能力。启动窗口期 started=False 不算掉线。
README 错误码表补 5005(此前遗漏)与 5006。
新增 15 个用例覆盖探活三态、is_connected() 自身抛错、边界重建/不重建/丢弃残留页/
重建失败、两个包装壳的分支、submit/pay 拒绝、runner 转 needs_human、/health 503。
真实 Chromium 崩溃无法在离线测试里制造,用例模拟的是 is_connected() 返回 False
这个唯一可观测信号,覆盖的是代码对该信号的反应而非崩溃本身;容器 HEALTHCHECK
真的触发重启这条链路尚未实跑验证。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
2026-08-20 16:01:47 +08:00 |
|
 q792602257andClaude Opus 4.6
|
65e3ed31f8
|
交易服务收敛为仅 rakuten:移除 rakuma 登录态与下单入口
trading 不再管理 ラクマ 的购物车购买、支付与订单监控。删除 auth_site /
auth_session / login_runner / models.AuthSite 中的 rakuma 分支与常量、
account.yaml.example 的 rakuma 段,并清理相关测试。scraping 侧的
ラクマ 抓取 API(/api/rakuma/*)保留不动。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
2026-07-28 11:50:07 +08:00 |
|
 q792602257andClaude Opus 5
|
104d7fef6b
|
拆分抓取与交易服务
把需要账号登录态的链路从抓取服务里拆出成独立进程。分界线不是「要不要登录」,
而是抓取无状态、幂等、可多开实例,而交易的写操作不可逆、登录态全局唯一、
订单监控是常驻轮询——同进程时抓取一扩容就会复制出 N 份登录态与 N 个轮询,
同一账号会被并发操作。
- app/shared:配置、错误码、日志、ApiResponse 信封 + Bearer 鉴权 + 异常处理器、
导航请求头构造器
- app/scraping:站点常量、会话、解析器与 10 个抓取接口,:31107,可多开
- app/trading:登录态查询/重载与健康检查,:31108,只能单实例
- 依赖方向锁为 scraping→shared、trading→shared,两侧互不 import;
tests/test_architecture.py 用 AST 检查 import 并校验两个 app 的路径不串
- 登录态 UA 在 trading 独立持有:与抓取 UA 值相同但变更理由不同,抓取 UA 为绕
反爬可随时调整,登录 UA 一改可能触发设备校验使已落盘 cookie 失效
- scripts/login.py 与 AuthSession 共用 auth_site.PROFILES 与 is_logged_in,判据只写一遍
- 同一镜像两个启动命令,交易容器覆盖 command 并设 RAKUTEN_HEALTH_PORT
同时带上此前未提交的 ラクマ 分类接口与登录态基础设施。
验证:239 个离线用例全绿;两个入口真实启动,/health 与鉴权正常。
未验证:真实探测登录态(当前开发机无外网,对站点的连接全部超时)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
2026-07-27 15:05:01 +08:00 |
|