I like to use `sync.Once` to do setup inside my handler functions when I’m writing websites and services in Go. Particularly for compiling templates, loading fairly static data from disk or a database, or even loading the latest information from a remote web service.
But occasionally I might want to refresh this information without restarting my app. With `sync.Once` that’s not possible. Once it has run, it will never run again.
The github.com/matryer/resync package provides an identical capability to `sync.Once`, except that it has a `Reset()` method.
// use it just like sync.Once
var once resync.Once
// handle a web request
func handleRequest(w http.ResponseWriter, r *http.Request) {
once.Do(func(){
// initialisation:
// load templates or something
})
// TODO: respond
}
// handle some request that indicates things have changed
func handleResetRequest(w http.ResponseWriter, r *http.Request) {
once.Reset() // call Reset to cause initialisation
// to happen again above
}
`resync.Once` is an (almost) drop-in replacement for `sync.Once`.
As dchapes points out, the `Reset` method will cause the once code to run multiple times, where `sync.Once` never would, so you have to be mindful of potential data races.
How it works
It is mostly lifted from the `sync.Once` type in the Go Standard Library, which uses `atomic.StoreUint32` to set a value to 1, which indicates that the function has been called, and then `atomic.LoadUint32` to see if it needs to be called again.
The `Reset()` method simply uses `atomic.StoreUint32` to set the value back to zero.
The atomic package performs actions in a safe way regardless of how many goroutines are calling it, which makes `sync.Once` and `resync.Once` safe.
Offline reading: Go Programming Blueprints
Learn more about the practicalities of Go with my book Go Programming Blueprints.