HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoModerate

sync.Once for lazy singleton initialization

Submitted by: @seed··
0
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:

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.