2025-08-19 18:32:09 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 轮询器(指数退避+超时+可取消)
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
import { PaymentApi } from "./PaymentApi";
|
2025-08-26 16:41:28 +08:00
|
|
|
|
import proto from 'db://assets/Scripts/proto/proto.pb.js';
|
2025-08-19 18:32:09 +08:00
|
|
|
|
|
|
|
|
|
|
export interface PollOptions {
|
|
|
|
|
|
maxDurationMs: number; // 轮询总时长(例如 2分钟)
|
|
|
|
|
|
startIntervalMs: number; // 初始间隔(例如 2s)
|
|
|
|
|
|
maxIntervalMs: number; // 最大间隔(例如 10s)
|
|
|
|
|
|
jitter?: boolean; // 抖动
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export class PaymentPoller {
|
|
|
|
|
|
private cancelled = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 取消轮询
|
|
|
|
|
|
cancel() { this.cancelled = true; }
|
|
|
|
|
|
|
|
|
|
|
|
// 轮询订单
|
2025-08-26 16:41:28 +08:00
|
|
|
|
async poll(orderId: string, opt: PollOptions, onTick?: (d: proto.cs.ICSQueryOrderRes) => void): Promise<proto.cs.ICSQueryOrderRes | null> {
|
2025-08-19 18:32:09 +08:00
|
|
|
|
const t0 = Date.now();
|
|
|
|
|
|
let interval = opt.startIntervalMs;
|
|
|
|
|
|
while (!this.cancelled) {
|
|
|
|
|
|
// 查询
|
2025-08-26 16:41:28 +08:00
|
|
|
|
let reqData = {orderId: orderId};
|
|
|
|
|
|
const r = await PaymentApi.I.queryOrder(reqData);
|
|
|
|
|
|
if (r.code === proto.cs.EnmRetCode.SUCCESS && r.data) {
|
2025-08-19 18:32:09 +08:00
|
|
|
|
// 回调
|
|
|
|
|
|
onTick?.(r.data);
|
2025-08-26 16:41:28 +08:00
|
|
|
|
if ([-1, 0].indexOf(r.data.status) !== -1) {
|
2025-08-19 18:32:09 +08:00
|
|
|
|
return r.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 退出条件
|
|
|
|
|
|
if (Date.now() - t0 > opt.maxDurationMs) return null;
|
|
|
|
|
|
// 等待
|
|
|
|
|
|
await this.sleep(this.jitter(interval, opt));
|
|
|
|
|
|
// 每次轮询后,interval 会按照 1.5 倍增长,直到达到最大间隔 maxIntervalMs,避免在短时间内重复请求
|
|
|
|
|
|
interval = Math.min(interval * 1.5, opt.maxIntervalMs);
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 用来暂停一定的时间(ms 毫秒),并让轮询进入等待状态
|
|
|
|
|
|
private sleep(ms: number) { return new Promise(res => setTimeout(res, ms)); }
|
|
|
|
|
|
|
|
|
|
|
|
// 用于实现抖动(随机化轮询间隔)
|
|
|
|
|
|
private jitter(base: number, opt: PollOptions) {
|
|
|
|
|
|
if (!opt.jitter) return base;
|
|
|
|
|
|
const delta = Math.min(500, Math.max(100, base * 0.1));
|
|
|
|
|
|
return base + (Math.random() * 2 - 1) * delta;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
export default PaymentPoller;
|