#避坑指南

这几个月对接 PetaX 单钱包时踩过的坑,按「现象 → 根因 → 应对」整理。全部是我方实测结论,能帮后来者少走弯路。

#1. settled-ticket 静默跳过陷阱 🔴 最容易误判

现象:结算通道(HTTP /petax/settled-ticket 或 RabbitMQ settled_win/loss)看起来一切正常,但对账页永远没有 MATCHED,petax_transactions 里也查不到 settled_ticket 记录。

根因:结算处理逻辑里,若回调携带的 username 在我方 petax_user_links 查不到对应用户,会打一条 warn 日志、返回成功(HTTP 200 / AMQP ACK)、但完全不写库。这是刻意设计(避免 PetaX 因失败而重发风暴),但代价是:

「PetaX 根本没推消息」和「消息到了但字段/用户名对不上、被静默丢弃」在数据库里长得一模一样——都是 0 行。

应对:不要只看 DB 判断结算通道通不通。要么挂一个临时消费者/抓包实测原始消息体(见下),要么检查回调日志(servicelog,integration=petax)确认调用次数与状态码。只有拿到原始 payload,才能分清是「没推」还是「推了但丢了」。

#2. Service API 前缀 520,和白名单无关

现象:出站调用 PetaX 的 Service API(如交易查询接口)返回 Cloudflare 520,带 token 不带 token结果一样。

根因:520 是「Cloudflare 连上了源站,但源站对这个路径返回未知错误」——即请求根本没走到鉴权层,是路由层面就失败了。第一反应容易归因到「IP 白名单没配」,但如果同一个域名下别的路径(比如认证/JWKS)能正常 200,就说明白名单没问题,是 URL 前缀本身配错了

应对:排查 520 时先做对照实验——同主机换一条已知能用的路径(如 JWKS)。两者结果不同,才能定位到底是网络/白名单问题,还是纯粹的路径/前缀问题。别急着去找 PetaX 要「加白名单」,先自证问题范围。

#3. 队列订阅成功 ≠ 有消息投递

现象:RabbitMQ 队列存在、消费者在线(能连、能订阅),但某类通知(如赢单/输单结算)长期零消息,而另一类(如开奖结果)正常收得到。

根因:队列「建好了」只代表可以订阅,是否往里面投递消息是发布方(PetaX)的事。队列存在不等于该通知已对我方商户启用。

应对:用「安全 peek」(basic.get 一条打印后 Nack(requeue=true) 放回,不销毁)加时间窗观察;若同一时间段内确定发生了对应业务事件(如真实结算了几张注单)却仍零消息,基本可判定是 PetaX 侧未启用该通知,需要主动去问,而不是继续排查自己的消费代码。

#4. 出口 IP 白名单:EOF ≠ 证书/配置问题

现象:mTLS 连接 RabbitMQ 时,TCP 能连上,但发出 ClientHello 后立刻 EOF,读到 0 字节。

根因:这不是证书错、cipher 不匹配、或 serverName 配错(那些情况会收到 TLS alert,读到的字节数 > 0)。read 0 bytes握手包都没收到回应就被挂断,是网络层直接丢弃——出口 IP 未在白名单。

应对:用 openssl s_client 直接测,看 read N bytes 是 0 还是有内容,一眼区分「网络层拒绝」和「协议层拒绝」,不要凭感觉调整证书配置。

#5. admin 时间选择器格式 vs 严格 RFC3339

现象:后台某些页面的时间范围选择器,选完提交后端点返回 400。

根因:前端表格组件在特定展示模式下,时间参数序列化成 YYYY-MM-DD HH:mm:ss(不带时区),而部分早期接口用严格 time.Parse(RFC3339) 解析——这个格式解析不出来。这个 bug 平时不容易被发现,因为它常被其他更显眼的错误(如 502)掩盖。

应对:后端解析时间参数应兼容三种常见形态(RFC3339、空格分隔的 datetime、纯日期),缺时区时按 UTC 处理,不要假设前端一定发 RFC3339。

#6. 幂等键设计:结算通知不限时间窗匹配

现象:如果对账逻辑简单地「时间窗内的投注 x 时间窗内的结算」两两比较,会把「投注在窗内、但结算稍晚才到(跨到窗外)」的正常场景误判成「未结算」。

应对:投注侧按时间窗过滤没问题,但去匹配结算记录时应该按 ticketId 全局查找(不限时间窗),因为结算总是滞后于投注发生。

#7. 房间(桌台)是静态清单,没有查询接口

现象:想通过接口动态获取当前可用房间列表,找不到对应 API。

根因:PetaX 没有「列房间」的 REST 接口,房间信息也不经 RabbitMQ 推送。房间是静态维护的清单,由 PetaX 一次性提供。

应对:不要设计成运行时动态拉取房间列表;房间 id 需要向 PetaX 索要,且要确认是哪个环境(staging/production)可用的真实 id——用错环境的房间 id 会导致玩家进入游戏后房间不存在。

#8. 首次玩家必须先开户,否则 launch 直接 502

现象:新用户第一次点开 PetaX 游戏,直接失败。

根因:PetaX 侧账号需要预先创建(开户/create-agent),不是首次登录时自动生成。若我方直接拿一个从未开户的映射账号去登录,登录本身就会失败,导致整个 launch 链路 502。

应对:launch 流程里,确保「首次玩家 → 先开户 → 再登录」的顺序被覆盖到,并且开户失败与登录失败要能在日志里区分开,否则很难判断是哪一步出的问题。

#9. 金额口径:两次换算,别把单位搞混

现象:核对金额时数字对不上,怀疑资金有误差。

根因:PetaX 侧金额是它自己的最小单位(minor units),要经过标度换算(scale)才能变成通用整数金额,再按汇率换算成我方统一余额的计价单位。两次换算叠加,如果只按面值直接比较,看起来会"对不上",但其实是单位不同。

应对:核对金额前先确认双方在比较同一层单位;展示层可以两个数字并列展示(不强行判等),避免把正常的换算误差当成资金问题去排查。