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 }