Skip to content

Conversation

@akshayutture-augment
Copy link
Contributor

@akshayutture-augment
Copy link
Contributor Author

@claude review this PR

1 similar comment
@akshayutture-augment
Copy link
Contributor Author

@claude review this PR

@claude
Copy link

claude bot commented Nov 20, 2025

Claude finished @akshayutture-augment's task —— View job


Code Review: Data Race Fix in GetWebAssets

I've reviewed the changes in pkg/api/webassets/webassets.go. This PR fixes a data race in the GetWebAssets function by adding proper synchronization.


Summary of Changes

The PR adds thread-safe access to the entryPointAssetsCache global variable using sync.RWMutex:

  • Added sync import
  • Introduced entryPointAssetsCacheMu (RWMutex) to guard entryPointAssetsCache
  • Modified GetWebAssets to use read/write locks appropriately

Review Findings

✅ Strengths

  1. Correct mutex usage: The implementation properly uses RLock/RUnlock for reads and Lock/Unlock for writes, which is the appropriate pattern for read-write mutexes.

  2. No lock contention on cache hit: The code reads entryPointAssetsCache while holding the read lock, stores it in ret, then releases the read lock before checking the condition. This minimizes lock hold time.

  3. Proper defer placement: The write lock deferral is correctly placed after acquiring the lock.

⚠️ Issues & Concerns

  1. Missing double-check pattern (pkg/api/webassets/webassets.go:48-49)

    Critical concurrency issue: After acquiring the write lock, the code doesn't re-check if another goroutine already populated the cache. This can lead to redundant work.

    Current code:

    entryPointAssetsCacheMu.Lock()
    defer entryPointAssetsCacheMu.Unlock()
    
    var err error
    var result *dtos.EntryPointAssets
    // proceeds to load assets even if cache was just populated

    Recommended fix:

    entryPointAssetsCacheMu.Lock()
    defer entryPointAssetsCacheMu.Unlock()
    
    // Double-check: another goroutine might have loaded the cache
    if cfg.Env != setting.Dev && entryPointAssetsCache != nil {
        return entryPointAssetsCache, nil
    }
    
    var err error
    var result *dtos.EntryPointAssets

    Why this matters: Without double-checking, if 100 goroutines simultaneously call GetWebAssets when the cache is empty, all will pass the initial read-locked check and queue up for the write lock. Each will then load the assets from disk/CDN sequentially, wasting resources.

  2. Potential nil return with nil error (pkg/api/webassets/webassets.go:69-70)

    If readWebAssetsFromCDN returns (nil, nil) when cdn != "", the code will set entryPointAssetsCache = nil and return (nil, nil). This violates the typical Go convention where error == nil implies success.

    However, looking at readWebAssetsFromCDN implementation, it appears to always return an error if the result is nil, so this may be a non-issue in practice. Still, defensive programming would add a check.

  3. Minor: Comment accuracy (pkg/api/webassets/webassets.go:54)

    The commented-out CDN URL includes a version number that may become stale:

    cdn := "" // "https://grafana-assets.grafana.net/grafana/10.3.0-64123/"

    Consider removing the specific version from the comment or marking it as an example.


Additional Observations

  1. Cache invalidation: The code only caches in non-Dev environments, which is correct for development. However, there's no mechanism to invalidate the cache at runtime if needed.

  2. Global state: The TODO comment acknowledges that global state isn't ideal. While this PR fixes the immediate data race, consider future refactoring to dependency-inject this cache.

  3. Error handling: The current implementation returns the last error encountered even if the cache was successfully populated. This seems intentional but could be clarified with a comment.


Verdict

Overall assessment: This is a solid fix for the data race issue. The core synchronization logic is correct and will prevent race conditions. The main concern is the missing double-check pattern, which could cause unnecessary resource usage under high concurrency but won't cause correctness issues.

Recommendation: Approve with suggestion to add double-check locking to optimize for concurrent access patterns.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants