Skip to content

Commit

Permalink
Fixed endless loop on settimeout.
Browse files Browse the repository at this point in the history
  • Loading branch information
coreybutler committed Oct 21, 2019
1 parent ab5a3a6 commit b1028cd
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ install:
- # Skip

script:
- go test
- go test -v
30 changes: 24 additions & 6 deletions timer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package timer

import "time"
import (
"time"
)

// Timer represents a monitor/iterator that runs
// a function on a given interval.
Expand All @@ -21,6 +23,11 @@ func (timer *Timer) Start() {
return
}

if timer.process != nil {
close(timer.process)
}

timer.running = true
timer.process = make(chan struct{})
timer.ticker = time.NewTicker(timer.interval)
timer.iterations = 0
Expand All @@ -31,31 +38,42 @@ func (timer *Timer) Start() {
select {
case <-timer.ticker.C:
go func(timer *Timer) {
if !timer.running {
return
}

timer.iterations = timer.iterations + 1

if timer.maxIntervals >= 0 && timer.iterations > timer.maxIntervals {
if timer.maxIntervals > 0 && timer.iterations > timer.maxIntervals {
timer.Stop()
return
}

timer.fn(timer.args)

if timer.maxIntervals == 0 {
timer.Stop()
return
}
}(timer)

case <-timer.process:
timer.Stop()
return
}
} else {
return
}
}
}(timer)

timer.running = true
}

// Stop the timer.
func (timer *Timer) Stop() {
close(timer.process)
timer.running = false
if timer.running {
close(timer.process)
timer.running = false
}
}

// Count represents the number of times the interval has been processed.
Expand Down
40 changes: 38 additions & 2 deletions timer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ func TestInterval(t *testing.T) {
counter = counter + 1
}, 300, &counter)

time.AfterFunc(time.Duration(1)*time.Second, func() {
timer := time.AfterFunc(time.Duration(1)*time.Second, func() {
if counter < 3 {
t.Errorf("Expected interval to run 3 times within a second. Only ran %v", counter)
}

if counter != interval.Count() {
t.Errorf("Expected %v iterations, only counted %v", counter, interval.Count())
}

interval.Stop()
})

defer timer.Stop()

time.Sleep(time.Duration(1400) * time.Millisecond)
}

func TestTimeout(t *testing.T) {
Expand All @@ -28,7 +34,7 @@ func TestTimeout(t *testing.T) {
counter = counter + 1
}, 300, &counter)

time.AfterFunc(time.Duration(1)*time.Second, func() {
timer := time.AfterFunc(time.Duration(1)*time.Second, func() {
if counter > 1 {
t.Errorf("Expected timeout to run once within a second. # Times Run: %v", counter)
}
Expand All @@ -37,4 +43,34 @@ func TestTimeout(t *testing.T) {
t.Errorf("Expected %v iterations, only counted %v", counter, interval.Count())
}
})

defer timer.Stop()

time.Sleep(time.Duration(500) * time.Millisecond)
}

func TestMultipleTimers(t *testing.T) {
counter := 0
var counterFn func(args ...interface{})

counterFn = func(args ...interface{}) {
counter = counter + 1

if counter < 3 {
_ = SetTimeout(counterFn, 300)
}
}

_ = SetTimeout(counterFn, 300)

timer := time.AfterFunc(time.Duration(2)*time.Second, func() {
if counter != 3 {
t.Errorf("Expected timeout to run 3 times within a second. # Times Run: %v", counter)
t.Fail()
}
})

defer timer.Stop()

time.Sleep(time.Duration(2500) * time.Millisecond)
}

0 comments on commit b1028cd

Please sign in to comment.