Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// Package repository contains persistence infrastructure helpers.
|
||||
//
|
||||
// DB pool lifetimes are clamped here because lib/pq starts watchCancel
|
||||
// goroutines for context-aware queries. If a cloud proxy silently drops idle
|
||||
// TCP without RST/FIN, those goroutines can block in Read until database/sql
|
||||
// retires the connection. This is a short-term mitigation; the long-term
|
||||
// follow-up is migrating PostgreSQL access to jackc/pgx/v5/stdlib.
|
||||
package repository
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultConnMaxLifetime = 30 * time.Minute
|
||||
defaultConnMaxIdleTime = 5 * time.Minute
|
||||
maxConfiguredConnAge = 24 * time.Hour
|
||||
)
|
||||
|
||||
type dbPoolSettings struct {
|
||||
MaxOpenConns int
|
||||
MaxIdleConns int
|
||||
ConnMaxLifetime time.Duration
|
||||
ConnMaxIdleTime time.Duration
|
||||
}
|
||||
|
||||
func clampDBPoolSettings(cfg *config.Config) dbPoolSettings {
|
||||
return dbPoolSettings{
|
||||
MaxOpenConns: cfg.Database.MaxOpenConns,
|
||||
MaxIdleConns: cfg.Database.MaxIdleConns,
|
||||
ConnMaxLifetime: clampDBPoolDuration("database.conn_max_lifetime_minutes", cfg.Database.ConnMaxLifetimeMinutes, defaultConnMaxLifetime),
|
||||
ConnMaxIdleTime: clampDBPoolDuration("database.conn_max_idle_time_minutes", cfg.Database.ConnMaxIdleTimeMinutes, defaultConnMaxIdleTime),
|
||||
}
|
||||
}
|
||||
|
||||
func clampDBPoolDuration(key string, minutes int, fallback time.Duration) time.Duration {
|
||||
if minutes <= 0 || minutes > int(maxConfiguredConnAge/time.Minute) {
|
||||
slog.Warn("database connection pool duration clamped",
|
||||
"key", key,
|
||||
"before", minutes,
|
||||
"after", int(fallback/time.Minute),
|
||||
)
|
||||
return fallback
|
||||
}
|
||||
|
||||
return time.Duration(minutes) * time.Minute
|
||||
}
|
||||
|
||||
func applyDBPoolSettings(db *sql.DB, cfg *config.Config) {
|
||||
settings := clampDBPoolSettings(cfg)
|
||||
db.SetMaxOpenConns(settings.MaxOpenConns)
|
||||
db.SetMaxIdleConns(settings.MaxIdleConns)
|
||||
db.SetConnMaxLifetime(settings.ConnMaxLifetime)
|
||||
db.SetConnMaxIdleTime(settings.ConnMaxIdleTime)
|
||||
|
||||
slog.Info("database connection pool configured",
|
||||
slog.Group("effective",
|
||||
slog.Int("max_open", settings.MaxOpenConns),
|
||||
slog.Int("max_idle", settings.MaxIdleConns),
|
||||
slog.Duration("max_lifetime", settings.ConnMaxLifetime),
|
||||
slog.Duration("max_idle_time", settings.ConnMaxIdleTime),
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user