One way that you could achieve this is by utilizing the for/select timeout idiom, there are a couple of similar methods of doing this. Take this trivial example:
package main
import (
"fmt"
"time"
)
func main() {
abort := make(chan struct{})
go func() {
for {
select {
case <-abort:
return
case <-time.After(1 * time.Second):
// replace fmt.Println() with the command you wish to run
fmt.Println("tick")
}
}
}()
// replace time.Sleep() with code waiting for 'abort' command input
time.Sleep(10 * time.Second)
abort <- struct{}{}
}
To modify this example to work in your circumstance place the code that you want to run in the <-time.After():
case, which (in this instance) will run once per second, if no other case is available to receive for that duration. And instead of time.Sleep()
which I placed at the end, put the code that will interrupt the <-time.After():
case, sending <- struct{}{}
on the abort
channel (or whatever you name it).
NOTE: In an earlier version of this answer I had abort as a chan bool
, as I like the clarity of <-abort true
and don't consider chan struct{}
to be as clear, I opted to change it in this example however, as <- struct{}{}
isn't unclear, especially once you've gotten used to the pattern.
Also, if you want the command to execute on each iteration of the for loop and not wait for a timeout then you can make that case default:
, remove <-time.After()
and it will run on each iteration of the loop where another channel is not ready to receive.
You can play with this example in the playground if you'd like, although it will not allow syscalls, or the default:
case example to be run in that environment.