diff --git a/common/signal/timer.go b/common/signal/timer.go index 16482101..30989b2f 100644 --- a/common/signal/timer.go +++ b/common/signal/timer.go @@ -12,6 +12,7 @@ type ActivityUpdater interface { type ActivityTimer struct { updated chan bool timeout chan time.Duration + closing chan bool } func (t *ActivityTimer) Update() { @@ -22,11 +23,17 @@ func (t *ActivityTimer) Update() { } func (t *ActivityTimer) SetTimeout(timeout time.Duration) { - t.timeout <- timeout + select { + case <-t.closing: + case t.timeout <- timeout: + } } func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) { - defer cancel() + defer func() { + cancel() + close(t.closing) + }() timeout := <-t.timeout if timeout == 0 { @@ -66,6 +73,7 @@ func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeo timer := &ActivityTimer{ timeout: make(chan time.Duration, 1), updated: make(chan bool, 1), + closing: make(chan bool), } timer.timeout <- timeout go timer.run(ctx, cancel) diff --git a/common/signal/timer_test.go b/common/signal/timer_test.go index a34cfbc1..f299b308 100644 --- a/common/signal/timer_test.go +++ b/common/signal/timer_test.go @@ -32,3 +32,15 @@ func TestActivityTimerUpdate(t *testing.T) { assert(ctx.Err(), IsNotNil) runtime.KeepAlive(timer) } + +func TestActivityTimerNonBlocking(t *testing.T) { + assert := With(t) + + ctx, cancel := context.WithCancel(context.Background()) + timer := CancelAfterInactivity(ctx, cancel, 0) + time.Sleep(time.Second * 1) + assert(ctx, HasDone) + timer.SetTimeout(0) + timer.SetTimeout(1) + timer.SetTimeout(2) +}