diff --git a/pkg/util/wait/wait.go b/pkg/util/wait/wait.go index b58a6288d0f..65f2e0b7618 100644 --- a/pkg/util/wait/wait.go +++ b/pkg/util/wait/wait.go @@ -20,6 +20,8 @@ import ( "errors" "math/rand" "time" + + "k8s.io/kubernetes/pkg/util/runtime" ) // For any test of the style: @@ -81,6 +83,7 @@ func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding b } func() { + defer runtime.HandleCrash() f() }() diff --git a/pkg/util/wait/wait_test.go b/pkg/util/wait/wait_test.go index e2ff86041aa..3c928424ac8 100644 --- a/pkg/util/wait/wait_test.go +++ b/pkg/util/wait/wait_test.go @@ -23,6 +23,8 @@ import ( "sync/atomic" "testing" "time" + + "k8s.io/kubernetes/pkg/util/runtime" ) func TestUntil(t *testing.T) { @@ -109,6 +111,41 @@ func TestJitterUntilReturnsImmediately(t *testing.T) { } } +func TestJitterUntilRecoversPanic(t *testing.T) { + // Save and restore crash handlers + originalReallyCrash := runtime.ReallyCrash + originalHandlers := runtime.PanicHandlers + defer func() { + runtime.ReallyCrash = originalReallyCrash + runtime.PanicHandlers = originalHandlers + }() + + called := 0 + handled := 0 + + // Hook up a custom crash handler to ensure it is called when a jitter function panics + runtime.ReallyCrash = false + runtime.PanicHandlers = []func(interface{}){ + func(p interface{}) { + handled++ + }, + } + + ch := make(chan struct{}) + JitterUntil(func() { + called++ + if called > 2 { + close(ch) + return + } + panic("TestJitterUntilRecoversPanic") + }, time.Millisecond, 1.0, true, ch) + + if called != 3 { + t.Errorf("Expected panic recovers") + } +} + func TestJitterUntilNegativeFactor(t *testing.T) { now := time.Now() ch := make(chan struct{})