scouting: Change background_task implementation
Instead of manually implementing a ticker, this patch switches over to
using `time.Ticker`. The functionality should be identical.
This patch also adds a small test to make sure that the bare
functionality is working.
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I54acfc5280b3541f3021dbe35d79e7db0adcc5f6
diff --git a/scouting/background_task/BUILD b/scouting/background_task/BUILD
index 20726ca..bdf7190 100644
--- a/scouting/background_task/BUILD
+++ b/scouting/background_task/BUILD
@@ -1,4 +1,4 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "background_task",
@@ -7,3 +7,9 @@
target_compatible_with = ["@platforms//cpu:x86_64"],
visibility = ["//visibility:public"],
)
+
+go_test(
+ name = "background_task_test",
+ srcs = ["background_task_test.go"],
+ embed = [":background_task"],
+)
diff --git a/scouting/background_task/background_task.go b/scouting/background_task/background_task.go
index 4fdb034..6980042 100644
--- a/scouting/background_task/background_task.go
+++ b/scouting/background_task/background_task.go
@@ -7,52 +7,46 @@
// A helper to run a function in the background at a specified interval.
// Can be used for a lot of different things.
type backgroundTask struct {
- doneChan chan<- bool
- checkStopped chan<- bool
- interval time.Duration
+ ticker *time.Ticker
+ stopRequested chan bool
+ done chan bool
}
func New(interval time.Duration) backgroundTask {
return backgroundTask{
- doneChan: make(chan bool, 1),
- checkStopped: make(chan bool, 1),
- interval: interval,
+ ticker: time.NewTicker(interval),
+ stopRequested: make(chan bool, 1),
+ done: make(chan bool, 1),
}
}
func (task *backgroundTask) Start(taskFunc func()) {
go func() {
- // Setting start time to a time prior so the function gets
- // called instantly when Start() called
- startTime := time.Now().Add(-task.interval - time.Minute)
+ // Signal the Stop() function below when the goroutine has
+ // finished executing.
+ defer func() { task.done <- true }()
+
+ // time.Ticker doesn't perform an immediate invocation.
+ // Instead, it waits for the specified duration before
+ // triggering the first tick. We pretend that there's a tick
+ // here by invoking the callback manually.
+ taskFunc()
+
for {
- curTime := time.Now()
- diff := curTime.Sub(startTime)
-
- if diff > task.interval {
+ select {
+ case <-task.stopRequested:
+ return
+ case <-task.ticker.C:
taskFunc()
- startTime = curTime
}
-
- if len(task.doneChan) != 0 {
- break
- }
-
- time.Sleep(time.Second)
}
-
- task.checkStopped <- true
}()
}
func (task *backgroundTask) Stop() {
- task.doneChan <- true
-
- for {
- if len(task.checkStopped) != 0 {
- close(task.doneChan)
- close(task.checkStopped)
- break
- }
- }
+ task.stopRequested <- true
+ task.ticker.Stop()
+ <-task.done
+ close(task.stopRequested)
+ close(task.done)
}
diff --git a/scouting/background_task/background_task_test.go b/scouting/background_task/background_task_test.go
new file mode 100644
index 0000000..5326d14
--- /dev/null
+++ b/scouting/background_task/background_task_test.go
@@ -0,0 +1,21 @@
+package background_task
+
+import (
+ "testing"
+ "time"
+)
+
+func TestBackgroundTask(t *testing.T) {
+ task := New(100 * time.Millisecond)
+ defer task.Stop()
+
+ counter := 0
+ task.Start(func() {
+ counter += 1
+ })
+
+ // Block until we've seeen 10 timer ticks.
+ for counter < 10 {
+ time.Sleep(100 * time.Millisecond)
+ }
+}