fix: batch admin billing reservations

This commit is contained in:
lyon
2026-06-14 01:14:07 +08:00
parent 96eb22a1c7
commit a8d58da005
+48 -5
View File
@@ -1220,6 +1220,7 @@ LIMIT $1`, limit)
defer rows.Close()
users := []adminBillingUserSummary{}
userIDs := []string{}
for rows.Next() {
var item adminBillingUserSummary
var lastUsed sql.NullTime
@@ -1236,19 +1237,61 @@ LIMIT $1`, limit)
item.APIKeys.LastUsedAt = &value
}
item.Credits.Available = item.Credits.Balance - item.Credits.Reserved
reservations, err := s.activeReservations(ctx, item.User.ID, 5)
if err != nil {
return nil, err
}
item.Reservations.Active = reservations
userIDs = append(userIDs, item.User.ID)
users = append(users, item)
}
if err := rows.Err(); err != nil {
return nil, err
}
reservations, err := s.activeReservationsForUsers(ctx, userIDs, 5)
if err != nil {
return nil, err
}
for i := range users {
users[i].Reservations.Active = reservations[users[i].User.ID]
}
return users, nil
}
func (s *Server) activeReservationsForUsers(ctx context.Context, userIDs []string, perUserLimit int) (map[string][]reservationSummaryRow, error) {
items := map[string][]reservationSummaryRow{}
if len(userIDs) == 0 {
return items, nil
}
placeholders := make([]string, len(userIDs))
args := make([]any, 0, len(userIDs)+1)
for i, userID := range userIDs {
placeholders[i] = "$" + strconv.Itoa(i+1)
args = append(args, userID)
}
limitParam := "$" + strconv.Itoa(len(args)+1)
args = append(args, perUserLimit)
query := `
SELECT user_id, id, service_id, estimated_credits, estimated_tokens, status, expires_at, created_at
FROM (
SELECT user_id, id, service_id, estimated_credits, estimated_tokens, status, expires_at, created_at,
row_number() OVER (PARTITION BY user_id ORDER BY expires_at ASC, created_at DESC) AS rn
FROM hwlab_billing_reservations
WHERE user_id IN (` + strings.Join(placeholders, ", ") + `) AND status = 'reserved' AND expires_at > now()
) ranked
WHERE rn <= ` + limitParam + `
ORDER BY expires_at ASC, created_at DESC`
rows, err := s.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var userID string
var item reservationSummaryRow
if err := rows.Scan(&userID, &item.ReservationID, &item.ServiceID, &item.EstimatedCredits, &item.EstimatedTokens, &item.Status, &item.ExpiresAt, &item.CreatedAt); err != nil {
return nil, err
}
items[userID] = append(items[userID], item)
}
return items, rows.Err()
}
func (s *Server) adminBillingTotals(ctx context.Context) (map[string]any, error) {
var totals struct {
Users int64