93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package walletnotice
|
||
|
||
import (
|
||
"context"
|
||
"log/slog"
|
||
"strings"
|
||
"time"
|
||
|
||
"hyapp/pkg/logx"
|
||
)
|
||
|
||
// WalletNoticeWorkerOptions 是钱包余额私有通知 worker 的运行参数。
|
||
type WalletNoticeWorkerOptions struct {
|
||
WorkerID string
|
||
PollInterval time.Duration
|
||
BatchSize int
|
||
LockTTL time.Duration
|
||
PublishTimeout time.Duration
|
||
MaxRetryCount int
|
||
InitialBackoff time.Duration
|
||
MaxBackoff time.Duration
|
||
}
|
||
|
||
// RunWalletBalanceWorker 持续消费 wallet_outbox 的 WalletBalanceChanged 事件。
|
||
func (s *Service) RunWalletBalanceWorker(ctx context.Context, options WalletNoticeWorkerOptions) {
|
||
options = normalizeWalletNoticeWorkerOptions(options, s.cfg.NodeID)
|
||
ticker := time.NewTicker(options.PollInterval)
|
||
defer ticker.Stop()
|
||
for {
|
||
processed, err := s.ProcessWalletBalanceNotices(ctx, options)
|
||
if err != nil && ctx.Err() == nil {
|
||
logx.Error(ctx, "notice_wallet_balance_batch_failed", err, slog.String("worker_id", options.WorkerID))
|
||
}
|
||
if processed >= options.BatchSize {
|
||
// 批次打满说明有积压,立即继续 drain,避免固定 tick 放大私有余额通知延迟。
|
||
continue
|
||
}
|
||
select {
|
||
case <-ctx.Done():
|
||
return
|
||
case <-ticker.C:
|
||
}
|
||
}
|
||
}
|
||
|
||
func normalizeWalletNoticeWorkerOptions(options WalletNoticeWorkerOptions, nodeID string) WalletNoticeWorkerOptions {
|
||
if strings.TrimSpace(options.WorkerID) == "" {
|
||
if strings.TrimSpace(nodeID) == "" {
|
||
nodeID = "notice"
|
||
}
|
||
options.WorkerID = "wallet-notice-" + nodeID
|
||
}
|
||
if options.PollInterval <= 0 {
|
||
options.PollInterval = time.Second
|
||
}
|
||
if options.BatchSize <= 0 {
|
||
options.BatchSize = 100
|
||
}
|
||
if options.LockTTL <= 0 {
|
||
options.LockTTL = 30 * time.Second
|
||
}
|
||
if options.PublishTimeout <= 0 {
|
||
options.PublishTimeout = 3 * time.Second
|
||
}
|
||
if options.MaxRetryCount <= 0 {
|
||
options.MaxRetryCount = 10
|
||
}
|
||
if options.InitialBackoff <= 0 {
|
||
options.InitialBackoff = 5 * time.Second
|
||
}
|
||
if options.MaxBackoff <= 0 {
|
||
options.MaxBackoff = 5 * time.Minute
|
||
}
|
||
return options
|
||
}
|
||
|
||
func walletNoticeBackoff(retryCount int, options WalletNoticeWorkerOptions) time.Duration {
|
||
if retryCount <= 0 {
|
||
return options.InitialBackoff
|
||
}
|
||
backoff := options.InitialBackoff
|
||
for i := 1; i < retryCount; i++ {
|
||
if backoff >= options.MaxBackoff/2 {
|
||
return options.MaxBackoff
|
||
}
|
||
backoff *= 2
|
||
}
|
||
if backoff > options.MaxBackoff {
|
||
return options.MaxBackoff
|
||
}
|
||
return backoff
|
||
}
|