Files
ttstd-infinite-canvas/backend/internal/app/billing_review.go

49 lines
1.2 KiB
Go

package app
import (
"context"
"log"
"time"
)
const billingReviewStaleAfter = 15 * time.Minute
// AuditBillingReview 执行只读账单巡检,提醒运维及时进入人工核对链路。
// 资金状态必须由人工依据上游证据结算或退款,巡检不能代替资金动作。
func (s *Service) AuditBillingReview() error {
stats, err := s.repo.StaleBillingReviewStats(time.Now(), billingReviewStaleAfter)
if err != nil {
return err
}
if stats.Total() == 0 {
return nil
}
oldest := ""
if stats.Oldest != nil {
oldest = stats.Oldest.UTC().Format(time.RFC3339)
}
log.Printf("billing review audit stale_orders=%d reserved=%d running=%d uncertain=%d oldest=%s", stats.Total(), stats.Reserved, stats.Running, stats.Uncertain, oldest)
return nil
}
func (s *Service) startBillingReviewAudit(ctx context.Context) {
audit := func() {
if err := s.AuditBillingReview(); err != nil {
log.Printf("billing review audit failed: %v", err)
}
}
s.runWorkerLoop(func(ctx context.Context) {
audit()
ticker := time.NewTicker(time.Hour)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
audit()
}
}
})
}