Concurrency
sync.Once: panicしてもDoは再実行しない
Once.Doの関数がpanicしても、そのOnceは完了済みとして扱われます。
Sourceonce.go
Go 1.22
package concurrencyexample
import "sync"
func CallsAfterOncePanic() (calls int) {
var once sync.Once
run := func() {
defer func() {
_ = recover()
}()
once.Do(func() {
calls++
panic("first call failed")
})
}
run()
run()
return calls
}Testonce_test.go
Go 1.22
package concurrencyexample
import "testing"
func TestSyncOnceはPanicしても再実行しない(t *testing.T) {
if got := CallsAfterOncePanic(); got != 1 {
t.Fatalf("CallsAfterOncePanic() = %d, want 1", got)
}
}01Assertion
このテストで確認できること
- Once.Doの最初の関数でpanicする
- recover後にDoを呼んでも関数本体は再実行されない
初期化失敗を再試行したい処理にはsync.Onceをそのまま使いません。エラーを返す初期化状態を明示して管理するか、Go 1.21以降ならOnceValuesなどを検討します。
OBSERVED RESULT
first once.Do → panic
second once.Do → skipped
calls → 1