update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
This commit is contained in:
69
utils/singleton/singleton.go
Normal file
69
utils/singleton/singleton.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package singleton
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/navidrome/navidrome/log"
|
||||
)
|
||||
|
||||
var (
|
||||
instances = map[string]interface{}{}
|
||||
pending = map[string]chan struct{}{}
|
||||
lock sync.RWMutex
|
||||
)
|
||||
|
||||
func GetInstance[T any](constructor func() T) T {
|
||||
var v T
|
||||
name := reflect.TypeOf(v).String()
|
||||
|
||||
// First check with read lock
|
||||
lock.RLock()
|
||||
if instance, ok := instances[name]; ok {
|
||||
defer lock.RUnlock()
|
||||
return instance.(T)
|
||||
}
|
||||
lock.RUnlock()
|
||||
|
||||
// Now check if someone is already creating this type
|
||||
lock.Lock()
|
||||
|
||||
// Check again with the write lock - someone might have created it
|
||||
if instance, ok := instances[name]; ok {
|
||||
lock.Unlock()
|
||||
return instance.(T)
|
||||
}
|
||||
|
||||
// Check if creation is pending
|
||||
wait, isPending := pending[name]
|
||||
if !isPending {
|
||||
// We'll be the one creating it
|
||||
pending[name] = make(chan struct{})
|
||||
wait = pending[name]
|
||||
}
|
||||
lock.Unlock()
|
||||
|
||||
// If someone else is creating it, wait for them
|
||||
if isPending {
|
||||
<-wait // Wait for creation to complete
|
||||
|
||||
// Now it should be in the instances map
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
return instances[name].(T)
|
||||
}
|
||||
|
||||
// We're responsible for creating the instance
|
||||
newInstance := constructor()
|
||||
|
||||
// Store it and signal other goroutines
|
||||
lock.Lock()
|
||||
instances[name] = newInstance
|
||||
close(wait) // Signal that creation is complete
|
||||
delete(pending, name) // Clean up
|
||||
log.Trace("Created new singleton", "type", name, "instance", fmt.Sprintf("%+v", newInstance))
|
||||
lock.Unlock()
|
||||
|
||||
return newInstance
|
||||
}
|
||||
Reference in New Issue
Block a user