perf: run balance/quota notification checks async

Move notifyBalanceLow and notifyAccountQuota to goroutines so the
threshold checking logic (DB settings reads, threshold calculation,
crossing detection) no longer blocks the request thread. Both are
fire-and-forget with panic recovery and log-only error handling.
This commit is contained in:
erio
2026-04-13 16:57:53 +08:00
parent 0ab0a01360
commit 20da7a8d07
2 changed files with 15 additions and 3 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.110.28
0.1.110.29
+14 -2
View File
@@ -7529,14 +7529,21 @@ func finalizePostUsageBilling(p *postUsageBillingParams, deps *billingDeps, resu
deps.deferredService.ScheduleLastUsedUpdate(p.Account.ID)
notifyBalanceLow(p, deps, result)
notifyAccountQuota(p, deps, result)
// Notification checks run async — all parameters are already captured,
// no dependency on the request context or upstream connection.
go notifyBalanceLow(p, deps, result)
go notifyAccountQuota(p, deps, result)
}
// notifyBalanceLow sends balance low notification after deduction.
// When result.NewBalance is available (from DB transaction RETURNING), it is used directly
// to reconstruct oldBalance, avoiding stale Redis reads and concurrent-deduction races.
func notifyBalanceLow(p *postUsageBillingParams, deps *billingDeps, result *UsageBillingApplyResult) {
defer func() {
if r := recover(); r != nil {
slog.Error("panic in notifyBalanceLow", "recover", r)
}
}()
if p.IsSubscriptionBill || p.Cost.ActualCost <= 0 || p.User == nil || deps.balanceNotifyService == nil {
slog.Debug("notifyBalanceLow: skipped",
"is_subscription", p.IsSubscriptionBill,
@@ -7573,6 +7580,11 @@ func resolveOldBalance(p *postUsageBillingParams, result *UsageBillingApplyResul
// When result.QuotaState is available (from DB transaction RETURNING), it is passed directly
// to avoid a separate DB read that may see stale or concurrently-modified data.
func notifyAccountQuota(p *postUsageBillingParams, deps *billingDeps, result *UsageBillingApplyResult) {
defer func() {
if r := recover(); r != nil {
slog.Error("panic in notifyAccountQuota", "recover", r)
}
}()
if p.Cost.TotalCost <= 0 || p.Account == nil || !p.Account.IsAPIKeyOrBedrock() || deps.balanceNotifyService == nil {
slog.Debug("notifyAccountQuota: skipped",
"total_cost", p.Cost.TotalCost,