feat: 优化分组缓存配置功能
This commit is contained in:
@@ -118,7 +118,7 @@ func (a *App) Start() error {
|
|||||||
}
|
}
|
||||||
logrus.Info("System settings initialized in DB.")
|
logrus.Info("System settings initialized in DB.")
|
||||||
|
|
||||||
a.settingsManager.Initialize(a.storage)
|
a.settingsManager.Initialize(a.storage, a.groupManager)
|
||||||
|
|
||||||
// 从数据库加载密钥到 Redis
|
// 从数据库加载密钥到 Redis
|
||||||
if err := a.keyPoolProvider.LoadKeysFromDB(); err != nil {
|
if err := a.keyPoolProvider.LoadKeysFromDB(); err != nil {
|
||||||
@@ -131,7 +131,7 @@ func (a *App) Start() error {
|
|||||||
if err := a.leaderService.WaitForInitializationToComplete(); err != nil {
|
if err := a.leaderService.WaitForInitializationToComplete(); err != nil {
|
||||||
return fmt.Errorf("follower failed to start: %w", err)
|
return fmt.Errorf("follower failed to start: %w", err)
|
||||||
}
|
}
|
||||||
a.settingsManager.Initialize(a.storage)
|
a.settingsManager.Initialize(a.storage, a.groupManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.groupManager.Initialize()
|
a.groupManager.Initialize()
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gpt-load/internal/db"
|
"gpt-load/internal/db"
|
||||||
"gpt-load/internal/models"
|
"gpt-load/internal/models"
|
||||||
"gpt-load/internal/store"
|
"gpt-load/internal/store"
|
||||||
"gpt-load/internal/syncer"
|
"gpt-load/internal/syncer"
|
||||||
|
"gpt-load/internal/types"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -16,38 +18,15 @@ import (
|
|||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SystemSettings 定义所有系统配置项
|
const SettingsUpdateChannel = "system_settings:updated"
|
||||||
// 使用结构体标签作为唯一事实来源
|
|
||||||
type SystemSettings struct {
|
|
||||||
// 基础参数
|
|
||||||
AppUrl string `json:"app_url" default:"" name:"项目地址" category:"基础参数" desc:"项目的基础 URL,用于拼接分组终端节点地址。系统配置优先于环境变量 APP_URL。"`
|
|
||||||
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" name:"日志保留天数" category:"基础参数" desc:"请求日志在数据库中的保留天数" validate:"min=1"`
|
|
||||||
|
|
||||||
// 服务超时
|
|
||||||
ServerReadTimeout int `json:"server_read_timeout" default:"120" name:"读取超时" category:"服务超时" desc:"HTTP 服务器读取超时时间(秒)" validate:"min=1"`
|
|
||||||
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" name:"写入超时" category:"服务超时" desc:"HTTP 服务器写入超时时间(秒)" validate:"min=1"`
|
|
||||||
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" name:"空闲超时" category:"服务超时" desc:"HTTP 服务器空闲超时时间(秒)" validate:"min=1"`
|
|
||||||
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" name:"优雅关闭超时" category:"服务超时" desc:"服务优雅关闭的等待超时时间(秒)" validate:"min=1"`
|
|
||||||
|
|
||||||
// 请求超时
|
|
||||||
RequestTimeout int `json:"request_timeout" default:"30" name:"请求超时" category:"请求超时" desc:"请求处理的总体超时时间(秒)" validate:"min=1"`
|
|
||||||
ResponseTimeout int `json:"response_timeout" default:"30" name:"响应超时" category:"请求超时" desc:"TLS 握手和响应头的超时时间(秒)" validate:"min=1"`
|
|
||||||
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" name:"空闲连接超时" category:"请求超时" desc:"空闲连接的超时时间(秒)" validate:"min=1"`
|
|
||||||
|
|
||||||
// 密钥配置
|
|
||||||
MaxRetries int `json:"max_retries" default:"3" name:"最大重试次数" category:"密钥配置" desc:"单个请求使用不同 Key 的最大重试次数" validate:"min=0"`
|
|
||||||
BlacklistThreshold int `json:"blacklist_threshold" default:"1" name:"黑名单阈值" category:"密钥配置" desc:"一个 Key 连续失败多少次后进入黑名单" validate:"min=0"`
|
|
||||||
KeyValidationIntervalMinutes int `json:"key_validation_interval_minutes" default:"60" name:"定时验证周期" category:"密钥配置" desc:"后台定时验证密钥的默认周期(分钟)" validate:"min=5"`
|
|
||||||
KeyValidationTaskTimeoutMinutes int `json:"key_validation_task_timeout_minutes" default:"60" name:"手动验证超时" category:"密钥配置" desc:"手动触发的全量验证任务的超时时间(分钟)" validate:"min=10"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateSettingsMetadata 使用反射从 SystemSettings 结构体动态生成元数据
|
// GenerateSettingsMetadata 使用反射从 SystemSettings 结构体动态生成元数据
|
||||||
func GenerateSettingsMetadata(s *SystemSettings) []models.SystemSettingInfo {
|
func GenerateSettingsMetadata(s *types.SystemSettings) []models.SystemSettingInfo {
|
||||||
var settingsInfo []models.SystemSettingInfo
|
var settingsInfo []models.SystemSettingInfo
|
||||||
v := reflect.ValueOf(s).Elem()
|
v := reflect.ValueOf(s).Elem()
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := range t.NumField() {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
fieldValue := v.Field(i)
|
fieldValue := v.Field(i)
|
||||||
|
|
||||||
@@ -86,12 +65,12 @@ func GenerateSettingsMetadata(s *SystemSettings) []models.SystemSettingInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DefaultSystemSettings 返回默认的系统配置
|
// DefaultSystemSettings 返回默认的系统配置
|
||||||
func DefaultSystemSettings() SystemSettings {
|
func DefaultSystemSettings() types.SystemSettings {
|
||||||
s := SystemSettings{}
|
s := types.SystemSettings{}
|
||||||
v := reflect.ValueOf(&s).Elem()
|
v := reflect.ValueOf(&s).Elem()
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := range t.NumField() {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
defaultTag := field.Tag.Get("default")
|
defaultTag := field.Tag.Get("default")
|
||||||
if defaultTag == "" {
|
if defaultTag == "" {
|
||||||
@@ -110,22 +89,24 @@ func DefaultSystemSettings() SystemSettings {
|
|||||||
|
|
||||||
// SystemSettingsManager 管理系统配置
|
// SystemSettingsManager 管理系统配置
|
||||||
type SystemSettingsManager struct {
|
type SystemSettingsManager struct {
|
||||||
syncer *syncer.CacheSyncer[SystemSettings]
|
syncer *syncer.CacheSyncer[types.SystemSettings]
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsUpdateChannel = "system_settings:updated"
|
|
||||||
|
|
||||||
// NewSystemSettingsManager creates a new, uninitialized SystemSettingsManager.
|
// NewSystemSettingsManager creates a new, uninitialized SystemSettingsManager.
|
||||||
func NewSystemSettingsManager() (*SystemSettingsManager, error) {
|
func NewSystemSettingsManager() *SystemSettingsManager {
|
||||||
return &SystemSettingsManager{}, nil
|
return &SystemSettingsManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type gm interface {
|
||||||
|
Invalidate() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize initializes the SystemSettingsManager with database and store dependencies.
|
// Initialize initializes the SystemSettingsManager with database and store dependencies.
|
||||||
func (sm *SystemSettingsManager) Initialize(store store.Store) error {
|
func (sm *SystemSettingsManager) Initialize(store store.Store, gm gm) error {
|
||||||
settingsLoader := func() (SystemSettings, error) {
|
settingsLoader := func() (types.SystemSettings, error) {
|
||||||
var dbSettings []models.SystemSetting
|
var dbSettings []models.SystemSetting
|
||||||
if err := db.DB.Find(&dbSettings).Error; err != nil {
|
if err := db.DB.Find(&dbSettings).Error; err != nil {
|
||||||
return SystemSettings{}, fmt.Errorf("failed to load system settings from db: %w", err)
|
return types.SystemSettings{}, fmt.Errorf("failed to load system settings from db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsMap := make(map[string]string)
|
settingsMap := make(map[string]string)
|
||||||
@@ -138,7 +119,7 @@ func (sm *SystemSettingsManager) Initialize(store store.Store) error {
|
|||||||
v := reflect.ValueOf(&settings).Elem()
|
v := reflect.ValueOf(&settings).Elem()
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
jsonToField := make(map[string]string)
|
jsonToField := make(map[string]string)
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := range t.NumField() {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
||||||
if jsonTag != "" {
|
if jsonTag != "" {
|
||||||
@@ -162,11 +143,18 @@ func (sm *SystemSettingsManager) Initialize(store store.Store) error {
|
|||||||
return settings, nil
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterLoader := func(newData types.SystemSettings) {
|
||||||
|
if err := gm.Invalidate(); err != nil {
|
||||||
|
logrus.Debugf("Failed to invalidate group manager cache after settings update: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
syncer, err := syncer.NewCacheSyncer(
|
syncer, err := syncer.NewCacheSyncer(
|
||||||
settingsLoader,
|
settingsLoader,
|
||||||
store,
|
store,
|
||||||
SettingsUpdateChannel,
|
SettingsUpdateChannel,
|
||||||
logrus.WithField("syncer", "system_settings"),
|
logrus.WithField("syncer", "system_settings"),
|
||||||
|
afterLoader,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create system settings syncer: %w", err)
|
return fmt.Errorf("failed to create system settings syncer: %w", err)
|
||||||
@@ -227,7 +215,7 @@ func (sm *SystemSettingsManager) EnsureSettingsInitialized() error {
|
|||||||
|
|
||||||
// GetSettings 获取当前系统配置
|
// GetSettings 获取当前系统配置
|
||||||
// If the syncer is not initialized, it returns default settings.
|
// If the syncer is not initialized, it returns default settings.
|
||||||
func (sm *SystemSettingsManager) GetSettings() SystemSettings {
|
func (sm *SystemSettingsManager) GetSettings() types.SystemSettings {
|
||||||
if sm.syncer == nil {
|
if sm.syncer == nil {
|
||||||
logrus.Warn("SystemSettingsManager is not initialized, returning default settings.")
|
logrus.Warn("SystemSettingsManager is not initialized, returning default settings.")
|
||||||
return DefaultSystemSettings()
|
return DefaultSystemSettings()
|
||||||
@@ -278,7 +266,7 @@ func (sm *SystemSettingsManager) UpdateSettings(settingsMap map[string]any) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
|
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
|
||||||
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) SystemSettings {
|
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) types.SystemSettings {
|
||||||
// 从系统配置开始
|
// 从系统配置开始
|
||||||
effectiveConfig := sm.GetSettings()
|
effectiveConfig := sm.GetSettings()
|
||||||
v := reflect.ValueOf(&effectiveConfig).Elem()
|
v := reflect.ValueOf(&effectiveConfig).Elem()
|
||||||
@@ -286,7 +274,7 @@ func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMa
|
|||||||
|
|
||||||
// 创建一个从 json 标签到字段名的映射
|
// 创建一个从 json 标签到字段名的映射
|
||||||
jsonToField := make(map[string]string)
|
jsonToField := make(map[string]string)
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := range t.NumField() {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
|
||||||
if jsonTag != "" {
|
if jsonTag != "" {
|
||||||
@@ -378,7 +366,7 @@ func (sm *SystemSettingsManager) ValidateSettings(settingsMap map[string]any) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DisplayCurrentSettings 显示当前系统配置信息
|
// DisplayCurrentSettings 显示当前系统配置信息
|
||||||
func (sm *SystemSettingsManager) DisplayCurrentSettings(settings SystemSettings) {
|
func (sm *SystemSettingsManager) DisplayCurrentSettings(settings types.SystemSettings) {
|
||||||
logrus.Info("Current System Settings:")
|
logrus.Info("Current System Settings:")
|
||||||
logrus.Infof(" App URL: %s", settings.AppUrl)
|
logrus.Infof(" App URL: %s", settings.AppUrl)
|
||||||
logrus.Infof(" Blacklist threshold: %d", settings.BlacklistThreshold)
|
logrus.Infof(" Blacklist threshold: %d", settings.BlacklistThreshold)
|
||||||
@@ -386,8 +374,10 @@ func (sm *SystemSettingsManager) DisplayCurrentSettings(settings SystemSettings)
|
|||||||
logrus.Infof(" Server timeouts: read=%ds, write=%ds, idle=%ds, shutdown=%ds",
|
logrus.Infof(" Server timeouts: read=%ds, write=%ds, idle=%ds, shutdown=%ds",
|
||||||
settings.ServerReadTimeout, settings.ServerWriteTimeout,
|
settings.ServerReadTimeout, settings.ServerWriteTimeout,
|
||||||
settings.ServerIdleTimeout, settings.ServerGracefulShutdownTimeout)
|
settings.ServerIdleTimeout, settings.ServerGracefulShutdownTimeout)
|
||||||
logrus.Infof(" Request timeouts: request=%ds, response=%ds, idle_conn=%ds",
|
logrus.Infof(" Request timeouts: request=%ds, connect=%ds, idle_conn=%ds",
|
||||||
settings.RequestTimeout, settings.ResponseTimeout, settings.IdleConnTimeout)
|
settings.RequestTimeout, settings.ConnectTimeout, settings.IdleConnTimeout)
|
||||||
|
logrus.Infof(" HTTP Client Pool: max_idle_conns=%d, max_idle_conns_per_host=%d",
|
||||||
|
settings.MaxIdleConns, settings.MaxIdleConnsPerHost)
|
||||||
logrus.Infof(" Request log retention: %d days", settings.RequestLogRetentionDays)
|
logrus.Infof(" Request log retention: %d days", settings.RequestLogRetentionDays)
|
||||||
logrus.Infof(" Key validation: interval=%dmin, task_timeout=%dmin",
|
logrus.Infof(" Key validation: interval=%dmin, task_timeout=%dmin",
|
||||||
settings.KeyValidationIntervalMinutes, settings.KeyValidationTaskTimeoutMinutes)
|
settings.KeyValidationIntervalMinutes, settings.KeyValidationTaskTimeoutMinutes)
|
||||||
@@ -424,10 +414,15 @@ func setFieldFromString(fieldValue reflect.Value, value string) error {
|
|||||||
|
|
||||||
func interfaceToInt(val any) (int, error) {
|
func interfaceToInt(val any) (int, error) {
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
|
case json.Number:
|
||||||
|
i64, err := v.Int64()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(i64), nil
|
||||||
case int:
|
case int:
|
||||||
return v, nil
|
return v, nil
|
||||||
case float64:
|
case float64:
|
||||||
// JSON unmarshals numbers into float64
|
|
||||||
if v != float64(int(v)) {
|
if v != float64(int(v)) {
|
||||||
return 0, fmt.Errorf("value is a float, not an integer: %v", v)
|
return 0, fmt.Errorf("value is a float, not an integer: %v", v)
|
||||||
}
|
}
|
||||||
@@ -448,6 +443,12 @@ func interfaceToString(val any) (string, bool) {
|
|||||||
// interfaceToBool is kept for GetEffectiveConfig
|
// interfaceToBool is kept for GetEffectiveConfig
|
||||||
func interfaceToBool(val any) (bool, bool) {
|
func interfaceToBool(val any) (bool, bool) {
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
|
case json.Number:
|
||||||
|
if s := v.String(); s == "1" {
|
||||||
|
return true, true
|
||||||
|
} else if s == "0" {
|
||||||
|
return false, true
|
||||||
|
}
|
||||||
case bool:
|
case bool:
|
||||||
return v, true
|
return v, true
|
||||||
case string:
|
case string:
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"gpt-load/internal/types"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/datatypes"
|
"gorm.io/datatypes"
|
||||||
@@ -38,21 +39,22 @@ type GroupConfig struct {
|
|||||||
|
|
||||||
// Group 对应 groups 表
|
// Group 对应 groups 表
|
||||||
type Group struct {
|
type Group struct {
|
||||||
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||||
Name string `gorm:"type:varchar(255);not null;unique" json:"name"`
|
EffectiveConfig types.SystemSettings `gorm:"-" json:"effective_config,omitempty"`
|
||||||
Endpoint string `gorm:"-" json:"endpoint"`
|
Name string `gorm:"type:varchar(255);not null;unique" json:"name"`
|
||||||
DisplayName string `gorm:"type:varchar(255)" json:"display_name"`
|
Endpoint string `gorm:"-" json:"endpoint"`
|
||||||
Description string `gorm:"type:varchar(512)" json:"description"`
|
DisplayName string `gorm:"type:varchar(255)" json:"display_name"`
|
||||||
Upstreams datatypes.JSON `gorm:"type:json;not null" json:"upstreams"`
|
Description string `gorm:"type:varchar(512)" json:"description"`
|
||||||
ChannelType string `gorm:"type:varchar(50);not null" json:"channel_type"`
|
Upstreams datatypes.JSON `gorm:"type:json;not null" json:"upstreams"`
|
||||||
Sort int `gorm:"default:0" json:"sort"`
|
ChannelType string `gorm:"type:varchar(50);not null" json:"channel_type"`
|
||||||
TestModel string `gorm:"type:varchar(255);not null" json:"test_model"`
|
Sort int `gorm:"default:0" json:"sort"`
|
||||||
ParamOverrides datatypes.JSONMap `gorm:"type:json" json:"param_overrides"`
|
TestModel string `gorm:"type:varchar(255);not null" json:"test_model"`
|
||||||
Config datatypes.JSONMap `gorm:"type:json" json:"config"`
|
ParamOverrides datatypes.JSONMap `gorm:"type:json" json:"param_overrides"`
|
||||||
APIKeys []APIKey `gorm:"foreignKey:GroupID" json:"api_keys"`
|
Config datatypes.JSONMap `gorm:"type:json" json:"config"`
|
||||||
LastValidatedAt *time.Time `json:"last_validated_at"`
|
APIKeys []APIKey `gorm:"foreignKey:GroupID" json:"api_keys"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
LastValidatedAt *time.Time `json:"last_validated_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIKey 对应 api_keys 表
|
// APIKey 对应 api_keys 表
|
||||||
|
@@ -2,6 +2,7 @@ package services
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"gpt-load/internal/config"
|
||||||
"gpt-load/internal/models"
|
"gpt-load/internal/models"
|
||||||
"gpt-load/internal/store"
|
"gpt-load/internal/store"
|
||||||
"gpt-load/internal/syncer"
|
"gpt-load/internal/syncer"
|
||||||
@@ -14,16 +15,22 @@ const GroupUpdateChannel = "groups:updated"
|
|||||||
|
|
||||||
// GroupManager manages the caching of group data.
|
// GroupManager manages the caching of group data.
|
||||||
type GroupManager struct {
|
type GroupManager struct {
|
||||||
syncer *syncer.CacheSyncer[map[string]*models.Group]
|
syncer *syncer.CacheSyncer[map[string]*models.Group]
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
store store.Store
|
store store.Store
|
||||||
|
settingsManager *config.SystemSettingsManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGroupManager creates a new, uninitialized GroupManager.
|
// NewGroupManager creates a new, uninitialized GroupManager.
|
||||||
func NewGroupManager(db *gorm.DB, store store.Store) *GroupManager {
|
func NewGroupManager(
|
||||||
|
db *gorm.DB,
|
||||||
|
store store.Store,
|
||||||
|
settingsManager *config.SystemSettingsManager,
|
||||||
|
) *GroupManager {
|
||||||
return &GroupManager{
|
return &GroupManager{
|
||||||
db: db,
|
db: db,
|
||||||
store: store,
|
store: store,
|
||||||
|
settingsManager: settingsManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +45,13 @@ func (gm *GroupManager) Initialize() error {
|
|||||||
groupMap := make(map[string]*models.Group, len(groups))
|
groupMap := make(map[string]*models.Group, len(groups))
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
g := *group
|
g := *group
|
||||||
|
g.EffectiveConfig = gm.settingsManager.GetEffectiveConfig(g.Config)
|
||||||
groupMap[g.Name] = &g
|
groupMap[g.Name] = &g
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"group_name": g.Name,
|
||||||
|
"group_config": g.Config,
|
||||||
|
"effective_config": g.EffectiveConfig,
|
||||||
|
}).Debug("Loaded group with effective config")
|
||||||
}
|
}
|
||||||
return groupMap, nil
|
return groupMap, nil
|
||||||
}
|
}
|
||||||
@@ -48,6 +61,7 @@ func (gm *GroupManager) Initialize() error {
|
|||||||
gm.store,
|
gm.store,
|
||||||
GroupUpdateChannel,
|
GroupUpdateChannel,
|
||||||
logrus.WithField("syncer", "groups"),
|
logrus.WithField("syncer", "groups"),
|
||||||
|
nil,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create group syncer: %w", err)
|
return fmt.Errorf("failed to create group syncer: %w", err)
|
||||||
|
@@ -23,6 +23,7 @@ type CacheSyncer[T any] struct {
|
|||||||
logger *logrus.Entry
|
logger *logrus.Entry
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
|
afterReload func(newValue T)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCacheSyncer creates and initializes a new CacheSyncer.
|
// NewCacheSyncer creates and initializes a new CacheSyncer.
|
||||||
@@ -31,6 +32,7 @@ func NewCacheSyncer[T any](
|
|||||||
store store.Store,
|
store store.Store,
|
||||||
channelName string,
|
channelName string,
|
||||||
logger *logrus.Entry,
|
logger *logrus.Entry,
|
||||||
|
afterReload func(newValue T),
|
||||||
) (*CacheSyncer[T], error) {
|
) (*CacheSyncer[T], error) {
|
||||||
s := &CacheSyncer[T]{
|
s := &CacheSyncer[T]{
|
||||||
loader: loader,
|
loader: loader,
|
||||||
@@ -38,6 +40,7 @@ func NewCacheSyncer[T any](
|
|||||||
channelName: channelName,
|
channelName: channelName,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
|
afterReload: afterReload,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.reload(); err != nil {
|
if err := s.reload(); err != nil {
|
||||||
@@ -85,6 +88,11 @@ func (s *CacheSyncer[T]) reload() error {
|
|||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
|
||||||
s.logger.Info("cache reloaded successfully")
|
s.logger.Info("cache reloaded successfully")
|
||||||
|
// After successfully reloading and updating the cache, trigger the hook.
|
||||||
|
if s.afterReload != nil {
|
||||||
|
s.logger.Debug("triggering afterReload hook")
|
||||||
|
s.afterReload(newData)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
// Package types defines common interfaces and types used across the application
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfigManager defines the interface for configuration management
|
// ConfigManager defines the interface for configuration management
|
||||||
type ConfigManager interface {
|
type ConfigManager interface {
|
||||||
GetAuthConfig() AuthConfig
|
GetAuthConfig() AuthConfig
|
||||||
@@ -19,29 +14,40 @@ type ConfigManager interface {
|
|||||||
ReloadConfig() error
|
ReloadConfig() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyServer defines the interface for proxy server
|
// SystemSettings 定义所有系统配置项
|
||||||
type ProxyServer interface {
|
type SystemSettings struct {
|
||||||
HandleProxy(c *gin.Context)
|
// 基础参数
|
||||||
Close()
|
AppUrl string `json:"app_url" default:"" name:"项目地址" category:"基础参数" desc:"项目的基础 URL,用于拼接分组终端节点地址。系统配置优先于环境变量 APP_URL。"`
|
||||||
|
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" name:"日志保留天数" category:"基础参数" desc:"请求日志在数据库中的保留天数" validate:"min=1"`
|
||||||
|
|
||||||
|
// 服务超时
|
||||||
|
ServerReadTimeout int `json:"server_read_timeout" default:"120" name:"读取超时" category:"服务超时" desc:"HTTP 服务器读取超时时间(秒)" validate:"min=1"`
|
||||||
|
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" name:"写入超时" category:"服务超时" desc:"HTTP 服务器写入超时时间(秒)" validate:"min=1"`
|
||||||
|
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" name:"空闲超时" category:"服务超时" desc:"HTTP 服务器空闲超时时间(秒)" validate:"min=1"`
|
||||||
|
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" name:"优雅关闭超时" category:"服务超时" desc:"服务优雅关闭的等待超时时间(秒)" validate:"min=1"`
|
||||||
|
|
||||||
|
// 请求超时
|
||||||
|
RequestTimeout int `json:"request_timeout" default:"600" name:"请求超时" category:"请求超时" desc:"转发请求的完整生命周期超时(秒),包括连接、重试等。" validate:"min=1"`
|
||||||
|
ConnectTimeout int `json:"connect_timeout" default:"5" name:"连接超时" category:"请求超时" desc:"与上游服务建立新连接的超时时间(秒)。" validate:"min=1"`
|
||||||
|
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" name:"空闲连接超时" category:"请求超时" desc:"HTTP 客户端中空闲连接的超时时间(秒)。" validate:"min=1"`
|
||||||
|
MaxIdleConns int `json:"max_idle_conns" default:"100" name:"最大空闲连接数" category:"请求超时" desc:"HTTP 客户端连接池中允许的最大空闲连接总数。" validate:"min=1"`
|
||||||
|
MaxIdleConnsPerHost int `json:"max_idle_conns_per_host" default:"10" name:"每主机最大空闲连接数" category:"请求超时" desc:"HTTP 客户端连接池对每个上游主机允许的最大空闲连接数。" validate:"min=1"`
|
||||||
|
|
||||||
|
// 密钥配置
|
||||||
|
MaxRetries int `json:"max_retries" default:"3" name:"最大重试次数" category:"密钥配置" desc:"单个请求使用不同 Key 的最大重试次数" validate:"min=0"`
|
||||||
|
BlacklistThreshold int `json:"blacklist_threshold" default:"1" name:"黑名单阈值" category:"密钥配置" desc:"一个 Key 连续失败多少次后进入黑名单" validate:"min=0"`
|
||||||
|
KeyValidationIntervalMinutes int `json:"key_validation_interval_minutes" default:"60" name:"定时验证周期" category:"密钥配置" desc:"后台定时验证密钥的默认周期(分钟)" validate:"min=5"`
|
||||||
|
KeyValidationTaskTimeoutMinutes int `json:"key_validation_task_timeout_minutes" default:"60" name:"手动验证超时" category:"密钥配置" desc:"手动触发的全量验证任务的超时时间(分钟)" validate:"min=10"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig represents server configuration
|
// ServerConfig represents server configuration
|
||||||
type ServerConfig struct {
|
type ServerConfig struct {
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
ReadTimeout int `json:"readTimeout"`
|
ReadTimeout int `json:"read_timeout"`
|
||||||
WriteTimeout int `json:"writeTimeout"`
|
WriteTimeout int `json:"write_timeout"`
|
||||||
IdleTimeout int `json:"idleTimeout"`
|
IdleTimeout int `json:"idle_timeout"`
|
||||||
GracefulShutdownTimeout int `json:"gracefulShutdownTimeout"`
|
GracefulShutdownTimeout int `json:"graceful_shutdown_timeout"`
|
||||||
}
|
|
||||||
|
|
||||||
// OpenAIConfig represents OpenAI API configuration
|
|
||||||
type OpenAIConfig struct {
|
|
||||||
BaseURL string `json:"baseUrl"`
|
|
||||||
BaseURLs []string `json:"baseUrls"`
|
|
||||||
RequestTimeout int `json:"requestTimeout"`
|
|
||||||
ResponseTimeout int `json:"responseTimeout"`
|
|
||||||
IdleConnTimeout int `json:"idleConnTimeout"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthConfig represents authentication configuration
|
// AuthConfig represents authentication configuration
|
||||||
@@ -53,26 +59,26 @@ type AuthConfig struct {
|
|||||||
// CORSConfig represents CORS configuration
|
// CORSConfig represents CORS configuration
|
||||||
type CORSConfig struct {
|
type CORSConfig struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
AllowedOrigins []string `json:"allowedOrigins"`
|
AllowedOrigins []string `json:"allowed_origins"`
|
||||||
AllowedMethods []string `json:"allowedMethods"`
|
AllowedMethods []string `json:"allowed_methods"`
|
||||||
AllowedHeaders []string `json:"allowedHeaders"`
|
AllowedHeaders []string `json:"allowed_headers"`
|
||||||
AllowCredentials bool `json:"allowCredentials"`
|
AllowCredentials bool `json:"allow_credentials"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PerformanceConfig represents performance configuration
|
// PerformanceConfig represents performance configuration
|
||||||
type PerformanceConfig struct {
|
type PerformanceConfig struct {
|
||||||
MaxConcurrentRequests int `json:"maxConcurrentRequests"`
|
MaxConcurrentRequests int `json:"max_concurrent_requests"`
|
||||||
KeyValidationPoolSize int `json:"KeyValidationPoolSize"`
|
KeyValidationPoolSize int `json:"key_validation_pool_size"`
|
||||||
EnableGzip bool `json:"enableGzip"`
|
EnableGzip bool `json:"enable_gzip"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogConfig represents logging configuration
|
// LogConfig represents logging configuration
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
Level string `json:"level"`
|
Level string `json:"level"`
|
||||||
Format string `json:"format"`
|
Format string `json:"format"`
|
||||||
EnableFile bool `json:"enableFile"`
|
EnableFile bool `json:"enable_file"`
|
||||||
FilePath string `json:"filePath"`
|
FilePath string `json:"file_path"`
|
||||||
EnableRequest bool `json:"enableRequest"`
|
EnableRequest bool `json:"enable_request"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DatabaseConfig represents database configuration
|
// DatabaseConfig represents database configuration
|
||||||
|
Reference in New Issue
Block a user