patterngoModerate
sync.Once for lazy singleton initialization
Viewed 0 times
sync.Oncesingletonlazy initializationonce.Dothread-safe initglobal instance
Problem
Initializing a singleton (DB connection, config) inside an if-nil check is not goroutine-safe and leads to race conditions under concurrent access.
Solution
Use sync.Once to guarantee exactly-once initialization:
For error-returning initialization, store the error alongside:
var (
instance *DB
once sync.Once
)
func GetDB() *DB {
once.Do(func() {
instance = openDatabase()
})
return instance
}For error-returning initialization, store the error alongside:
var (
db *DB
dbErr error
dbOnce sync.Once
)
func GetDB() (*DB, error) {
dbOnce.Do(func() {
db, dbErr = openDatabase()
})
return db, dbErr
}Why
sync.Once uses atomic operations and a mutex internally to guarantee that the function passed to Do is called exactly once, even under concurrent access from many goroutines.
Gotchas
- If the function panics, Once considers it done — subsequent calls will not retry the initialization
- Once cannot be reset; to support retrying on error, store the error and check it separately or use a custom pattern
- Avoid calling once.Do inside a function that is itself called from once.Do — it will deadlock
Revisions (0)
No revisions yet.