Skip to content

可靠性、健康与错误 ​

送达语意 ​

  1. 至少一次送达:本平台以 (sourceId, table, seq) 去重。
    • 同一个 seq、内容相同(以范式 JSON 比较,键的顺序不影响):忽略并照常 ack。
    • 同一个 seq、内容不同:nack SEQ_CONFLICT。
  2. 每条视频流内保序:来源必须依 seq 递增送出;不同桌之间不保证顺序。
  3. 缺口检测:事件的 prev 不等于本平台已接收的最后一个 seq 时,回 resync {table, from},来源必须从 from 之后重送。
  4. ack 在持久化之后才送:事件写入后才回 ack,ack 是累积式的:{"B001": 1538} 表示这条视频流 ≤ 1538 的事件都已接收。
  5. 重连续传:WebSocket 连接创建时,welcome.resume 给出每条视频流已 ack 的最后 seq,来源从它之后补送。HTTPS 来源可以调用 GET /ingest/v1/resume?tables=…。
  6. 来源保留期:来源至少要保留 24 小时内可重送的事件。
  7. 无法重送时:送出 table.snapshot(gap: true)后接续实时事件。这笔快照不要求 prev 对上,但 seq 仍须大于本平台已接收的最后一个 seq;之后的事件从快照的 seq 接续。缺口期间未完成的局会转为异常局,超时自动作废退款。
  8. 视频流单一拥有者:同一条视频流同时只能经由一条 WebSocket 连接送达。新连接在 hello 声明同一张桌时会接管,旧连接再送这张桌的事件会收到 nack STREAM_TAKEN_OVER。
  9. 未绑定的来源桌:事件照常 ack 并归档,但不套用;平台完成绑定后开始套用。

响应格式 ​

HTTPS(POST /ingest/v1/events、/validate)一次回复整批的结果:

json
{
  "acks": { "B001": 1538 },
  "nacks": [{ "code": "INVALID_EVENT", "table": "B002", "seq": 77, "message": "data.result.cards.P1: must match ^(A|[2-9]|10|J|Q|K)[SHDC]$" }],
  "resync": [{ "table": "B003", "from": 812 }]
}

WebSocket 则逐一送出 {"op":"ack","acks":{…}}、{"op":"nack",…}、{"op":"resync","table":"…","from":…}。

  • nack 带 accepted: true 时(RESULT_INCONSISTENT),事件已接收并持久化,视频流照常前进,只是警告。
  • 其他 nack 表示事件没有被接收,视频流停在前一笔;修正后以相同的 seq 重送。
  • 同一批中某条视频流出现 nack 或 resync 后,这条视频流在这批里剩下的事件都不处理;其他视频流不受影响。
  • 所有事件(包含被拒绝的)都会写入原始归档,作为争议与审核依据。

健康与心跳 ​

  • 心跳(不占用视频流序号)每 5 秒送一次,逐桌回报健康状态 ok、degraded、down:

    json
    {"op":"heartbeat","ts":"2026-09-24T03:00:35.000Z","tables":{"B001":"ok","B002":"down"}}
  • 来源知道某张桌的上游已经中断时,要立即把该桌标成 down,本平台会马上停止该桌收注。

  • 15 秒内没有心跳也没有事件,视为来源失联:所有绑定的桌停止收注;进行中的局等待恢复,超时自动作废退款。

  • 最后一条 WebSocket 连接中断时,这条连接负责的桌也会立即停止收注;来源重连并送出心跳或事件后恢复。

错误码 ​

代码意义来源应采取的行动
UNAUTHORIZED签名错误、时间窗外、nonce 重复、传输方式未开放或 IP 不在白名单检查密钥、时钟与设置
SOURCE_DISABLED来源已禁用联系平台
UNSUPPORTED_VERSIONv 不支持升级
TABLE_NOT_ALLOWED这个来源无权发布这张桌联系平台
INVALID_EVENT结构错误、字段不合法修正这一笔后,以相同 seq 重送
SEQ_GAP(resync)prev 对不上从 from 之后重送
SEQ_CONFLICT同一个 seq 内容不同来源端错误,需要人工排查
RESULT_CONFLICT同一个 rev 的结果不同(保留;目前版本维持原结果并记录,不返回 nack)改用 round.correct
RESULT_INCONSISTENT牌面与点数、输赢或补牌规则不符(牛牛:重复的牌、牌型或输赢与牌面不符、发牌顺序不符,见牛牛)已接收但保留待审;可以送 round.correct 更正
STREAM_TAKEN_OVER这张桌已由新连接接管停止在旧连接送这张桌
RATE_LIMITED超出流量(保留;目前版本不返回)退避后重试

WebSocket 关闭码:

关闭码意义
4001认证失败(例如 hello.source 与凭证不符)
4002版本不支持
4003来源已禁用
4008违反限制(消息或批量过大)
1012本平台重新启动:立即重连并续传

重连退避:1 秒起、每次加倍、上限 30 秒,另加随机延迟。

来源信任等级 ​

平台为每个来源设置信任等级,决定自动化程度。每一种情况都有自动处置,差别只在护栏的宽严:

等级不完整结果(complete: false)结果验证不一致结果修正(round.correct)结算后作废(round.cancel)
trusted可结算的投注区照常结算,其余退款以来源的 winner 结算并标记自动重算自动冲回
standard同上保留不结算,超时自动作废退款护栏内自动重算;护栏外维持原结果并列为争议局同左
restricted同上同上同上同上

护栏:修正或作废在结算后 30 分钟内送达,而且新结果完整、通过补牌规则验证。超出护栏时不动任何金额,只记为争议局。

WebSocket 对话示例 ​

text
← {"op":"welcome","v":1,"session":"s_8f2…","heartbeat":5,"maxBatch":500,"maxInflight":2000,
   "resume":{"B001":1530,"D001":0},"serverTime":"2026-09-24T03:00:29.950Z"}
→ {"op":"hello","v":1,"source":"acme-live","agent":"acme-feeder/2.0",
   "tables":["B001","D001"],"capabilities":{"cardByCard":true,"countdown":true,"snapshot":true,"replayHours":168}}
→ {"op":"events","events":[
     {"v":1,"type":"round.open","table":"B001","seq":1531,"prev":1530,"ts":"2026-09-24T03:00:30.000Z",
      "game":"baccarat","shoe":"260924-03","round":12,"roundKey":"B001-260924-03-12",
      "data":{"closesAt":"2026-09-24T03:00:55.000Z","betSeconds":25}}]}
← {"op":"ack","acks":{"B001":1531}}
→ {"op":"heartbeat","ts":"2026-09-24T03:00:35.000Z","tables":{"B001":"ok","D001":"ok"}}
→ {"op":"events","events":[
     {"v":1,"type":"round.close","table":"B001","seq":1532,"prev":1531,"ts":"2026-09-24T03:00:55.010Z",
      "game":"baccarat","shoe":"260924-03","round":12,"roundKey":"B001-260924-03-12","data":{}},
     {"v":1,"type":"round.result","table":"B001","seq":1538,"prev":1532,"ts":"2026-09-24T03:01:20.400Z",
      "game":"baccarat","shoe":"260924-03","round":12,"roundKey":"B001-260924-03-12",
      "data":{"rev":1,"complete":true,"result":{
        "cards":{"P1":"2C","B1":"4H","P2":"3D","B2":"2S","P3":"10S"},
        "player":5,"banker":6,"winner":"B","playerPair":false,"bankerPair":false}}}]}
← {"op":"ack","acks":{"B001":1538}}
  • seq 可以不连号(上例 1532 之后是 1538),但每笔的 prev 必须等于前一笔的 seq。
  • hello 的 source 必须与 X-Source-Id 相同,否则以 4001 关闭。
  • hello.tables 声明这条连接负责的桌,新连接会接管同一张桌。

上线流程 ​

  1. 向平台申请来源:代号、类型、传输方式、IP 白名单 → 取得 HMAC 密钥。
  2. 先在测试环境(elite-dev-ingest.ewin888.com)对接;可以用 POST /ingest/v1/validate 干跑,或用 GFI 事件验证器 检查事件格式。
  3. 通过兼容性检查:断线续传(任意 seq)、resync 重送、无法重送时送快照、心跳与 down 标记、修正与作废、时钟偏移 < 500 ms、错误事件的处理。
  4. 平台把来源桌绑定到公开桌并设置优先级后上线。

elite 租户集成 API v1