feat: Rock 兑换支持上游异步 pending 并记录发货全链路报文
问题:上游 0666.pro 兑换返回 HTTP 200 + status=pending(官方处理中), 旧逻辑仅凭「没有 error 字段」就判定成功并写 redeemed 终态,导致本地显示 已发货而上游仍是 bound,且 redeemed 为硬终态无法自愈。 后端: - RedeemSkin 改为三态判定(success / pending / failed),不再无 error 即成功 - 新增 redeeming「发货处理中」状态;pending 不写 redeemed_at/fulfill_id - 成功落库前二次 refresh 确认上游 redeemed 或 redeemed_at 才置终态 - 新增确认 worker:20s 轮询、30s→5m 指数退避、110001 全局冷却 60s、 15 分钟未确认仅告警不回退,确认后同步订单为 delivered 并触发回调 - pending 期间禁止重复兑换,订单保持 delivering,不下发发货成功回调 - 新增 rock_delivery_logs 表与记录器:入站参数、内部状态、上游请求/响应 原文全部留档,保留 180 天 - 分配/绑定校验/刷新/导入/删除/回收站/统计/客服查询全部适配 redeeming - 迁移 026:redeeming 跟踪字段、部分索引与报文日志表 前端: - Token 列表新增「发货处理中」筛选项、标签与超时提示 - 删除/回收站纳入 redeeming 危险状态 - 历史抽屉拆为「状态历史 / 发货报文」双页签,按 trace 展示报文详情 - 买家发货页在 pending 时提示官方处理中,无需重复提交 测试:新增 pending 不落终态、异常响应不误判、重复提交不重复兑换、 确认后同步订单、保持 pending 并退避 5 个用例;go build/vet/test 与 前端构建均通过。
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
-- 026: Rock 异步发货(上游 pending)状态 + 发货全链路报文日志
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_requested_at timestamptz;
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_checked_at timestamptz;
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_attempts integer NOT NULL DEFAULT 0;
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_next_retry_at timestamptz;
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_last_message text NOT NULL DEFAULT '';
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_last_error text NOT NULL DEFAULT '';
|
||||
ALTER TABLE rock_tokens ADD COLUMN IF NOT EXISTS redeem_timeout_warned_at timestamptz;
|
||||
|
||||
COMMENT ON COLUMN rock_tokens.redeem_requested_at IS '首次提交上游兑换的时间(pending 起点,15 分钟未确认触发告警)';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_checked_at IS '最近一次查询上游兑换结果的时间';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_attempts IS '已执行的兑换结果轮询次数';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_next_retry_at IS '下一次允许轮询上游的时间(指数退避)';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_last_message IS '上游最近一次返回的处理说明';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_last_error IS '最近一次轮询/兑换错误';
|
||||
COMMENT ON COLUMN rock_tokens.redeem_timeout_warned_at IS '超过 15 分钟仍未确认时写入告警时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rock_tokens_redeem_next_retry_at
|
||||
ON rock_tokens (redeem_next_retry_at)
|
||||
WHERE status = 'redeeming';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rock_delivery_logs (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
trace_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
token_id BIGINT NOT NULL DEFAULT 0,
|
||||
upstream_token_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
order_no VARCHAR(128) NOT NULL DEFAULT '',
|
||||
step VARCHAR(40) NOT NULL DEFAULT '',
|
||||
direction VARCHAR(16) NOT NULL DEFAULT '',
|
||||
status VARCHAR(16) NOT NULL DEFAULT '',
|
||||
http_method VARCHAR(8) NOT NULL DEFAULT '',
|
||||
http_url TEXT NOT NULL DEFAULT '',
|
||||
http_status INTEGER NOT NULL DEFAULT 0,
|
||||
request_headers TEXT NOT NULL DEFAULT '',
|
||||
request_body TEXT NOT NULL DEFAULT '',
|
||||
response_headers TEXT NOT NULL DEFAULT '',
|
||||
response_body TEXT NOT NULL DEFAULT '',
|
||||
duration_ms INTEGER NOT NULL DEFAULT 0,
|
||||
error_message TEXT NOT NULL DEFAULT '',
|
||||
actor_user_id BIGINT,
|
||||
actor_ip VARCHAR(64) NOT NULL DEFAULT '',
|
||||
user_agent VARCHAR(512) NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
finished_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rock_delivery_logs_trace
|
||||
ON rock_delivery_logs (trace_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_rock_delivery_logs_token
|
||||
ON rock_delivery_logs (token_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rock_delivery_logs_order
|
||||
ON rock_delivery_logs (order_no, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rock_delivery_logs_created_at
|
||||
ON rock_delivery_logs (created_at DESC);
|
||||
Reference in New Issue
Block a user