chore(sync): 上游同步 - 快照导入 upstream/main@e70fe1b9(v1.6.5)并重放本项目差异

This commit is contained in:
2026-10-12 11:52:01 +08:00
parent c9979a4a2b
commit 43c3dd3568
167 changed files with 5794 additions and 7804 deletions

View File

@@ -0,0 +1,86 @@
package database
import (
"context"
"fmt"
"maps"
"net"
"strconv"
"strings"
"time"
"github.com/jackc/pgx/v5"
)
// defaultIdleInTransactionSessionTimeout 限制事务内等待下一条命令的时间,
// 避免卡住的 idle in transaction 会话长期持有锁。DSN 显式配置时以 DSN 为准。
const defaultIdleInTransactionSessionTimeout = "5min"
var libpqKeepaliveParams = []string{"keepalives", "keepalives_idle", "keepalives_interval", "keepalives_count"}
// configurePostgresConnection 在每次建立物理连接前调整 pgx 连接配置。
func configurePostgresConnection(_ context.Context, config *pgx.ConnConfig) error {
// stdlib 传入的是浅拷贝,RuntimeParams 与连接器共享,修改前必须复制,否则会跨连接累积。
config.RuntimeParams = maps.Clone(config.RuntimeParams)
if config.RuntimeParams == nil {
config.RuntimeParams = make(map[string]string)
}
if err := applyLibpqKeepalives(config); err != nil {
return err
}
if _, exists := config.RuntimeParams["idle_in_transaction_session_timeout"]; !exists {
// PostgreSQL 按顺序处理 options,DSN 原有 options 放在后面,同名设置以 DSN 为准。
options := "-c idle_in_transaction_session_timeout=" + defaultIdleInTransactionSessionTimeout
if existing := strings.TrimSpace(config.RuntimeParams["options"]); existing != "" {
options += " " + existing
}
config.RuntimeParams["options"] = options
}
return nil
}
// applyLibpqKeepalives 消费 libpq 的 keepalives* 参数并应用到 TCP 拨号器。
// pgx 不识别这些参数,会把它们当作服务端运行参数发送,导致 PostgreSQL 拒绝连接。
// 未配置任何 keepalives* 参数时保持 pgx 默认拨号器(Go 默认 keepalive)不变。
func applyLibpqKeepalives(config *pgx.ConnConfig) error {
values := make(map[string]int)
for _, key := range libpqKeepaliveParams {
raw, ok := config.RuntimeParams[key]
if !ok {
continue
}
delete(config.RuntimeParams, key)
value, err := strconv.Atoi(strings.TrimSpace(raw))
if err != nil || value < 0 || (key == "keepalives" && value > 1) {
return fmt.Errorf("invalid PostgreSQL connection parameter %s=%q", key, raw)
}
values[key] = value
}
if len(values) == 0 {
return nil
}
dialer := &net.Dialer{Timeout: config.ConnectTimeout}
if enabled, ok := values["keepalives"]; ok && enabled == 0 {
dialer.KeepAlive = -1
} else {
// 未配置的项使用 Go 默认值(0);libpq 的 0 表示操作系统默认值,对应 Go 的 -1。
setting := func(key string) int {
value, ok := values[key]
if !ok {
return 0
}
if value == 0 {
return -1
}
return value
}
dialer.KeepAliveConfig = net.KeepAliveConfig{
Enable: true,
Idle: time.Duration(setting("keepalives_idle")) * time.Second,
Interval: time.Duration(setting("keepalives_interval")) * time.Second,
Count: setting("keepalives_count"),
}
}
config.DialFunc = dialer.DialContext
return nil
}