Philipp Schrader | a9a7939 | 2023-03-25 13:28:31 -0700 | [diff] [blame] | 1 | package background_task |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 2 | |
| 3 | import ( |
| 4 | "time" |
| 5 | ) |
| 6 | |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 7 | // A helper to run a function in the background at a specified interval. |
| 8 | // Can be used for a lot of different things. |
| 9 | type backgroundTask struct { |
Philipp Schrader | b15f4bd | 2023-03-25 14:21:38 -0700 | [diff] [blame] | 10 | ticker *time.Ticker |
| 11 | stopRequested chan bool |
| 12 | done chan bool |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 13 | } |
| 14 | |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 15 | func New(interval time.Duration) backgroundTask { |
| 16 | return backgroundTask{ |
Philipp Schrader | b15f4bd | 2023-03-25 14:21:38 -0700 | [diff] [blame] | 17 | ticker: time.NewTicker(interval), |
| 18 | stopRequested: make(chan bool, 1), |
| 19 | done: make(chan bool, 1), |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 20 | } |
| 21 | } |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 22 | |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 23 | func (task *backgroundTask) Start(taskFunc func()) { |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 24 | go func() { |
Philipp Schrader | b15f4bd | 2023-03-25 14:21:38 -0700 | [diff] [blame] | 25 | // Signal the Stop() function below when the goroutine has |
| 26 | // finished executing. |
| 27 | defer func() { task.done <- true }() |
| 28 | |
| 29 | // time.Ticker doesn't perform an immediate invocation. |
| 30 | // Instead, it waits for the specified duration before |
| 31 | // triggering the first tick. We pretend that there's a tick |
| 32 | // here by invoking the callback manually. |
| 33 | taskFunc() |
| 34 | |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 35 | for { |
Philipp Schrader | b15f4bd | 2023-03-25 14:21:38 -0700 | [diff] [blame] | 36 | select { |
| 37 | case <-task.stopRequested: |
| 38 | return |
| 39 | case <-task.ticker.C: |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 40 | taskFunc() |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 41 | } |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 42 | } |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 43 | }() |
| 44 | } |
| 45 | |
Philipp Schrader | 417ab8a | 2023-03-25 15:16:01 -0700 | [diff] [blame] | 46 | // Stops the background task from within the background task. The Stop() |
| 47 | // function still needs to be called from outside the task. |
| 48 | func (task *backgroundTask) StopFromWithinTask() { |
| 49 | task.stopRequested <- true |
| 50 | } |
| 51 | |
Philipp Schrader | 3f0e36f | 2023-03-25 13:49:41 -0700 | [diff] [blame] | 52 | func (task *backgroundTask) Stop() { |
Philipp Schrader | b15f4bd | 2023-03-25 14:21:38 -0700 | [diff] [blame] | 53 | task.stopRequested <- true |
| 54 | task.ticker.Stop() |
| 55 | <-task.done |
| 56 | close(task.stopRequested) |
| 57 | close(task.done) |
Philipp Schrader | c49eaf7 | 2023-02-26 16:56:52 -0800 | [diff] [blame] | 58 | } |