fix: cap mysql connection pool

This commit is contained in:
richjohnrambo
2026-09-27 18:36:00 +08:00
parent 4f69dc302b
commit 5bf68727fa
4 changed files with 40 additions and 9 deletions
+3 -1
View File
@@ -1,7 +1,9 @@
{ {
"listen": ":6061", "listen": ":6061",
"mysql": { "mysql": {
"dsn": "root:root@tcp(127.0.0.1:3306)/meeting_im?parseTime=true&charset=utf8mb4,utf8&loc=Local" "dsn": "root:root@tcp(127.0.0.1:3306)/meeting_im?parseTime=true&charset=utf8mb4,utf8&loc=Local",
"max_open_conns": 15,
"max_idle_conns": 5
}, },
"redis": { "redis": {
"addr": "127.0.0.1:6379", "addr": "127.0.0.1:6379",
+16 -2
View File
@@ -24,7 +24,9 @@ type Config struct {
} }
type MySQLConfig struct { type MySQLConfig struct {
DSN string `json:"dsn"` DSN string `json:"dsn"`
MaxOpenConns int `json:"max_open_conns"`
MaxIdleConns int `json:"max_idle_conns"`
} }
type RedisConfig struct { type RedisConfig struct {
@@ -90,7 +92,9 @@ func defaultConfig() *Config {
return &Config{ return &Config{
Listen: ":6061", Listen: ":6061",
MySQL: MySQLConfig{ MySQL: MySQLConfig{
DSN: "root:root@tcp(127.0.0.1:3306)/meeting_im?parseTime=true&charset=utf8mb4,utf8&loc=Local", DSN: "root:root@tcp(127.0.0.1:3306)/meeting_im?parseTime=true&charset=utf8mb4,utf8&loc=Local",
MaxOpenConns: 15,
MaxIdleConns: 5,
}, },
Redis: RedisConfig{ Redis: RedisConfig{
Addr: "127.0.0.1:6379", Addr: "127.0.0.1:6379",
@@ -120,6 +124,8 @@ func defaultConfig() *Config {
func applyEnv(cfg *Config) { func applyEnv(cfg *Config) {
setString(&cfg.Listen, "IM_WORKBENCH_LISTEN") setString(&cfg.Listen, "IM_WORKBENCH_LISTEN")
setString(&cfg.MySQL.DSN, "IM_WORKBENCH_MYSQL_DSN") setString(&cfg.MySQL.DSN, "IM_WORKBENCH_MYSQL_DSN")
setInt(&cfg.MySQL.MaxOpenConns, "IM_WORKBENCH_MYSQL_MAX_OPEN_CONNS")
setInt(&cfg.MySQL.MaxIdleConns, "IM_WORKBENCH_MYSQL_MAX_IDLE_CONNS")
setString(&cfg.Redis.Addr, "IM_WORKBENCH_REDIS_ADDR") setString(&cfg.Redis.Addr, "IM_WORKBENCH_REDIS_ADDR")
setString(&cfg.Redis.Username, "IM_WORKBENCH_REDIS_USERNAME") setString(&cfg.Redis.Username, "IM_WORKBENCH_REDIS_USERNAME")
setString(&cfg.Redis.Password, "IM_WORKBENCH_REDIS_PASSWORD") setString(&cfg.Redis.Password, "IM_WORKBENCH_REDIS_PASSWORD")
@@ -214,6 +220,14 @@ func setString(target *string, key string) {
} }
} }
func setInt(target *int, key string) {
if value := strings.TrimSpace(os.Getenv(key)); value != "" {
if parsed, err := strconv.Atoi(value); err == nil {
*target = parsed
}
}
}
func setBool(target *bool, key string) { func setBool(target *bool, key string) {
switch strings.ToLower(strings.TrimSpace(os.Getenv(key))) { switch strings.ToLower(strings.TrimSpace(os.Getenv(key))) {
case "1", "true", "yes", "on": case "1", "true", "yes", "on":
+15
View File
@@ -23,4 +23,19 @@ func TestDefaultConfigUsesMeetingIMDatabase(t *testing.T) {
if !strings.Contains(cfg.MySQL.DSN, "/meeting_im?") { if !strings.Contains(cfg.MySQL.DSN, "/meeting_im?") {
t.Fatalf("default mysql dsn = %q, want meeting_im database", cfg.MySQL.DSN) t.Fatalf("default mysql dsn = %q, want meeting_im database", cfg.MySQL.DSN)
} }
if cfg.MySQL.MaxOpenConns != 15 || cfg.MySQL.MaxIdleConns != 5 {
t.Fatalf("default mysql pool = %d/%d, want 15/5", cfg.MySQL.MaxOpenConns, cfg.MySQL.MaxIdleConns)
}
}
func TestApplyEnvOverridesMySQLPool(t *testing.T) {
t.Setenv("IM_WORKBENCH_MYSQL_MAX_OPEN_CONNS", "12")
t.Setenv("IM_WORKBENCH_MYSQL_MAX_IDLE_CONNS", "4")
cfg := defaultConfig()
applyEnv(cfg)
if cfg.MySQL.MaxOpenConns != 12 || cfg.MySQL.MaxIdleConns != 4 {
t.Fatalf("mysql pool = %d/%d, want 12/4", cfg.MySQL.MaxOpenConns, cfg.MySQL.MaxIdleConns)
}
} }
+6 -6
View File
@@ -58,7 +58,7 @@ func SetUIDKey(encoded string) error {
} }
func Open(cfg config.MySQLConfig) (*Store, error) { func Open(cfg config.MySQLConfig) (*Store, error) {
st, err := openDSN(cfg.DSN) st, err := openDSN(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -66,13 +66,13 @@ func Open(cfg config.MySQLConfig) (*Store, error) {
return st, nil return st, nil
} }
func openDSN(dsn string) (*Store, error) { func openDSN(cfg config.MySQLConfig) (*Store, error) {
db, err := sqlx.Open("mysql", dsn) db, err := sqlx.Open("mysql", cfg.DSN)
if err != nil { if err != nil {
return nil, err return nil, err
} }
db.SetMaxOpenConns(30) db.SetMaxOpenConns(cfg.MaxOpenConns)
db.SetMaxIdleConns(10) db.SetMaxIdleConns(cfg.MaxIdleConns)
db.SetConnMaxLifetime(30 * time.Minute) db.SetConnMaxLifetime(30 * time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
@@ -80,7 +80,7 @@ func openDSN(dsn string) (*Store, error) {
_ = db.Close() _ = db.Close()
return nil, err return nil, err
} }
return &Store{db: db, dsn: dsn}, nil return &Store{db: db, dsn: cfg.DSN}, nil
} }
func (s *Store) tenant() int64 { func (s *Store) tenant() int64 {