Skip to content
Open
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
16 changes: 13 additions & 3 deletions pkg/api/webassets/webassets.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"os"
"path/filepath"
"sync"

"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/services/licensing"
Expand All @@ -31,12 +32,21 @@ type EntryPointInfo struct {
} `json:"assets,omitempty"`
}

var entryPointAssetsCache *dtos.EntryPointAssets = nil
var (
entryPointAssetsCacheMu sync.RWMutex // guard entryPointAssetsCache
entryPointAssetsCache *dtos.EntryPointAssets // TODO: get rid of global state
)

func GetWebAssets(ctx context.Context, cfg *setting.Cfg, license licensing.Licensing) (*dtos.EntryPointAssets, error) {
if cfg.Env != setting.Dev && entryPointAssetsCache != nil {
return entryPointAssetsCache, nil
entryPointAssetsCacheMu.RLock()
ret := entryPointAssetsCache
entryPointAssetsCacheMu.RUnlock()

if cfg.Env != setting.Dev && ret != nil {
return ret, nil
}
entryPointAssetsCacheMu.Lock()
defer entryPointAssetsCacheMu.Unlock()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Cache Race: Redundant Expensive Reloads

The double-checked locking pattern is incomplete. After acquiring the write lock at line 48, the code doesn't re-check if entryPointAssetsCache was already populated by another goroutine. Multiple concurrent requests can pass the initial nil check (lines 41-47) and all proceed to reload assets, causing redundant expensive I/O operations (file reads or HTTP requests) instead of using the cache populated by the first goroutine.

Fix in Cursor Fix in Web


var err error
var result *dtos.EntryPointAssets
Expand Down
Loading