0ae7769abe
- gateway: TestSettleConcurrentSameOrder 真并发钉住 MarkAttemptPaid 行锁不变量 (文件型 sqlite,规避 in-memory cache=shared 的 SQLITE_LOCKED_SHAREDCACHE)。 - gateway: e2e_fullchain_test.go 补下单→回调→settle→webhook 实际 HTTP 投递→ delivered 整链(httptest server + 真实 store.WebhookStore/webhook.Notifier)。 - reconcile: main.go 装配抽到 reconcile.Assemble(+Runner.TaskNames 访问器), 补 assembly_test.go 钉住 7 个后台任务全部注册 + crypto 缺渠道/interval=0 分支。 - alipay: 补验签健壮性(未知多余字段/字段乱序/中文unicode/空值字段),意外定位 vendor Encoder 对空值字段的真实语义与官方文档描述不同,已记录在测试注释。 - money: 补 TestZeroDecimalCurrencyJPYNotSupported,记录 JPY/KRW 当前未注册进 exponents(接入会先踩 ErrUnknownCurrency,不是乘除法坑)。
45 lines
2.6 KiB
Go
45 lines
2.6 KiB
Go
package reconcile
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/wangjia/pay/config"
|
|
"github.com/wangjia/pay/internal/accounts"
|
|
"github.com/wangjia/pay/internal/gateway"
|
|
"github.com/wangjia/pay/internal/provider"
|
|
"github.com/wangjia/pay/internal/store"
|
|
)
|
|
|
|
// Assemble builds the full P6 background-reconcile Runner: order-expire /
|
|
// usage-refresh / refund-apply-sweep / refund-stuck-alert (local, DB-only,
|
|
// AddLocal — run synchronously once at startup by main.go's RunOnceLocal) +
|
|
// sync-pending / paid-spotcheck (network, Add — first tick handles it) +
|
|
// crypto warm(直跑)+ crypto-orphan-scan(AddCryptoJobs,network,只在 crypto 渠道
|
|
// 已注册时挂载).
|
|
//
|
|
// 抽出这个函数纯粹是为了让"预期任务集合是否都注册上"能被直接单测(main.go 原先把
|
|
// 这段写死在 main() 里,main() 本身因为要拉真实 DB/HTTP server 不适合单测——见
|
|
// assembly_test.go)。main.go 对应 `if config.C.Reconcile.Enabled` 分支现在只是薄薄
|
|
// 一层:调这里 + RunOnceLocal/Start/日志,行为与抽取前逐行一致,未改任何调度语义。
|
|
func Assemble(orderStore *store.OrderStore, refundStore *store.RefundStore, usage *UsageSource,
|
|
gw *gateway.Gateway, pReg *provider.Registry, acctReg *accounts.Registry,
|
|
orphanStore *store.OrphanStore, rc config.ReconcileConfig) *Runner {
|
|
runner := NewRunner()
|
|
// 纯本地(DB-only)任务用 AddLocal:会被启动预热 RunOnceLocal 同步跑一遍。
|
|
runner.AddLocal("order-expire", time.Duration(rc.ExpireEverySec)*time.Second,
|
|
OrderExpirerTask(orderStore, time.Duration(rc.OrderTTLMin)*time.Minute, time.Now))
|
|
runner.AddLocal("usage-refresh", time.Duration(rc.UsageEverySec)*time.Second,
|
|
RefreshUsageTask(usage))
|
|
runner.AddLocal("refund-apply-sweep", time.Duration(rc.RefundApplyEverySec)*time.Second,
|
|
RefundApplyTask(orderStore, refundStore, time.Duration(rc.RefundApplyLookbackMin)*time.Minute, time.Now, 200))
|
|
runner.AddLocal("refund-stuck-alert", time.Duration(rc.RefundApplyEverySec)*time.Second,
|
|
RefundStuckAlertTask(refundStore, time.Duration(rc.RefundStuckWarnMin)*time.Minute, time.Now))
|
|
// 网络型(出网 HTTP,10-15s 超时)任务用 Add:启动预热不跑,交各自 ticker 首跳。
|
|
runner.Add("sync-pending", time.Duration(rc.SyncEverySec)*time.Second,
|
|
SyncPendingTask(gw, 100))
|
|
runner.Add("paid-spotcheck", time.Duration(rc.SpotCheckEverySec)*time.Second,
|
|
PaidSpotCheckTask(orderStore, pReg, time.Duration(rc.SpotCheckWindowMin)*time.Minute, time.Now))
|
|
AddCryptoJobs(runner, pReg, acctReg, orderStore, orphanStore, rc) // crypto 预留冷启动 Warm(直跑,不受影响)+ 孤儿扫描(网络型,交 ticker 首跳)
|
|
return runner
|
|
}
|