Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/ai/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func providerLabel(provider string) string {
}

func LoadRuntimeConfig() (*RuntimeConfig, error) {
setting, err := model.GetGeneralSetting()
setting, err := model.GetGeneralSettingCached()
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/ai/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func HandleExecuteContinue(c *gin.Context) {
}

func HandleGetGeneralSetting(c *gin.Context) {
setting, err := model.GetGeneralSetting()
setting, err := model.GetGeneralSettingCached()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to load general setting: %v", err)})
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/kubectl_terminal_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (h *KubectlTerminalHandler) HandleKubectlTerminalWebSocket(c *gin.Context)
return
}

setting, err := model.GetGeneralSetting()
setting, err := model.GetGeneralSettingCached()
if err != nil {
h.sendErrorMessage(conn, fmt.Sprintf("Failed to load settings: %v", err))
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/node_terminal_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (h *NodeTerminalHandler) HandleNodeTerminalWebSocket(c *gin.Context) {
h.sendErrorMessage(conn, fmt.Sprintf("Node %s not found", nodeName))
return
}
setting, err := model.GetGeneralSetting()
setting, err := model.GetGeneralSettingCached()
if err != nil {
log.Printf("Failed to load general setting: %v", err)
h.sendErrorMessage(conn, fmt.Sprintf("Failed to load settings: %v", err))
Expand Down
42 changes: 42 additions & 0 deletions pkg/model/general_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package model
import (
"errors"
"strings"
"sync"

"github.com/zxh326/kite/pkg/common"
"gorm.io/gorm"
Expand Down Expand Up @@ -63,6 +64,46 @@ func DefaultGeneralAIModelByProvider(provider string) string {
}
}

// gsMu + gsCache implement a singleton cache for the GeneralSetting row.
// Read-path uses RLock (~10-25 ns); miss falls through to DB with double-check.
var (
gsMu sync.RWMutex
gsCache *GeneralSetting
)

// GetGeneralSettingCached returns the cached GeneralSetting singleton.
// On cache miss it falls back to GetGeneralSetting (DB + normalisation)
// and stores the result. Thread-safe via double-checked locking.
func GetGeneralSettingCached() (*GeneralSetting, error) {
gsMu.RLock()
if c := gsCache; c != nil {
gsMu.RUnlock()
return c, nil
}
gsMu.RUnlock()

// Cache miss — acquire write lock and double-check.
gsMu.Lock()
defer gsMu.Unlock()
if gsCache != nil {
return gsCache, nil
}
s, err := GetGeneralSetting()
if err != nil {
return nil, err
}
gsCache = s
return s, nil
}

// InvalidateGeneralSettingCache clears the cached singleton so the next
// read reloads from the database. Called from UpdateGeneralSetting.
func InvalidateGeneralSettingCache() {
gsMu.Lock()
gsCache = nil
gsMu.Unlock()
}

func GetGeneralSetting() (*GeneralSetting, error) {
var setting GeneralSetting
err := DB.First(&setting, 1).Error
Expand Down Expand Up @@ -132,6 +173,7 @@ func UpdateGeneralSetting(updates map[string]interface{}) (*GeneralSetting, erro
return nil, err
}
applyRuntimeGeneralSetting(setting)
InvalidateGeneralSettingCache()
return setting, nil
}

Expand Down