视频会议保存
This commit is contained in:
96
backend/go-service/pkg/db/mysql.go
Normal file
96
backend/go-service/pkg/db/mysql.go
Normal file
@@ -0,0 +1,96 @@
|
||||
// Package db 提供数据库连接管理(MySQL 二连接实例,用于外部 LLM 配置中心)
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/echochat/backend/config"
|
||||
"github.com/echochat/backend/pkg/logs"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// LLMSourceDB 包装外部 LLM 配置库连接
|
||||
//
|
||||
// 之所以用 wrapper 而不是直接返回 *gorm.DB:
|
||||
// - 主库 (*gorm.DB) 在 Wire 中已被全局注入到所有 DAO,不能让 LLM 库被误用为业务库
|
||||
// - Enabled=false 时仍要构造一个空 wrapper,避免下游 nil 引用
|
||||
// - 下游 DAO 通过 IsEnabled() 决定是否走数据库路径或返回未配置错误
|
||||
type LLMSourceDB struct {
|
||||
db *gorm.DB
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// IsEnabled 是否真正连接了 MySQL;false 时禁止访问 DB()
|
||||
func (l *LLMSourceDB) IsEnabled() bool {
|
||||
return l != nil && l.enabled && l.db != nil
|
||||
}
|
||||
|
||||
// DB 获取底层 GORM 实例(仅 IsEnabled() == true 时返回非 nil)
|
||||
// 调用方应先判 IsEnabled,再使用返回值。
|
||||
func (l *LLMSourceDB) DB() *gorm.DB {
|
||||
if !l.IsEnabled() {
|
||||
return nil
|
||||
}
|
||||
return l.db
|
||||
}
|
||||
|
||||
// NewLLMSourceDB 初始化外部 LLM 配置 MySQL 连接
|
||||
//
|
||||
// 行为约定:
|
||||
// - cfg.Enabled == false:跳过连接,返回 enabled=false 的空 wrapper(不报错),保证 Wire 流程不阻塞
|
||||
// - cfg.Enabled == true 但连接失败:返回 error,由 main 决定是否硬失败
|
||||
//
|
||||
// 之所以连接失败时硬报错而不是 graceful degrade:
|
||||
// - 用户已显式 enabled=true,预期就要用,沉默降级反而难排查
|
||||
// - 转写功能未启用时只需保持 enabled=false 即可
|
||||
func NewLLMSourceDB(cfg *config.LLMSourceConfig) (*LLMSourceDB, error) {
|
||||
funcName := "db.NewLLMSourceDB"
|
||||
ctx := context.Background()
|
||||
|
||||
if cfg == nil || !cfg.Enabled {
|
||||
logs.Info(ctx, funcName, "外部 LLM 配置库未启用,跳过 MySQL 连接(语音转写功能将不可用)")
|
||||
return &LLMSourceDB{enabled: false}, nil
|
||||
}
|
||||
|
||||
logs.Info(ctx, funcName, "正在连接外部 LLM 配置 MySQL",
|
||||
zap.String("host", cfg.Host),
|
||||
zap.Int("port", cfg.Port),
|
||||
zap.String("dbname", cfg.DBName),
|
||||
)
|
||||
|
||||
gdb, err := gorm.Open(mysql.Open(cfg.DSN()), &gorm.Config{
|
||||
Logger: &zapGormLogger{},
|
||||
})
|
||||
if err != nil {
|
||||
logs.Error(ctx, funcName, "MySQL 连接失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("连接 LLM 配置 MySQL 失败: %w", err)
|
||||
}
|
||||
|
||||
sqlDB, err := gdb.DB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取 MySQL 底层 sql.DB 失败: %w", err)
|
||||
}
|
||||
maxIdle := cfg.MaxIdleConns
|
||||
if maxIdle <= 0 {
|
||||
maxIdle = 5
|
||||
}
|
||||
maxOpen := cfg.MaxOpenConns
|
||||
if maxOpen <= 0 {
|
||||
maxOpen = 20
|
||||
}
|
||||
sqlDB.SetMaxIdleConns(maxIdle)
|
||||
sqlDB.SetMaxOpenConns(maxOpen)
|
||||
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||
|
||||
if err := sqlDB.Ping(); err != nil {
|
||||
logs.Error(ctx, funcName, "MySQL Ping 失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("ping LLM 配置 MySQL 失败: %w", err)
|
||||
}
|
||||
|
||||
logs.Info(ctx, funcName, "外部 LLM 配置 MySQL 连接成功")
|
||||
return &LLMSourceDB{db: gdb, enabled: true}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user