You can use a similar code than Go by Example: Timeouts
c2 := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
c2 <- "result 2"
}()
select {
case res := <-c2:
fmt.Println(res)
case <-time.After(3 * time.Second):
fmt.Println("timeout 2")
}
In your case, the go func
would exec
the echo
, while the main function would wait for a timeout, or the execution of go func
, whichever comes first.
That is: https://goplay.space/#MtHh3CenMcn
package main
import (
"fmt"
"os/exec"
"time"
)
func main() {
c2 := make(chan string, 1)
go func() {
out, err := exec.Command("echo", "hello").Output()
fmt.Println(err)
c2 <- string(out)
}()
select {
case res := <-c2:
fmt.Println("'" + res + "'")
case <-time.After(3 * time.Second):
fmt.Println("timeout 2")
}
}
If the echo
takes more than 3 seconds, the timeout would kick in.
Note that the example does not work i a playground setting, because:
"echo": executable file not found in $PATH
But in your local environment, it should work.
A different approach, based on context: https://goplay.space/#F2GtMLgVAAI
package main
import (
"context"
"fmt"
"os/exec"
)
func main() {
gen := func(ctx context.Context) <-chan string {
dst := make(chan string)
go func() {
out, err := exec.Command("echo", "hello").Output()
fmt.Println(err)
for {
select {
case <-ctx.Done():
return // returning not to leak the goroutine
case dst <- string(out):
return
}
}
}()
return dst
}
ctx, cancel := context.WithTimeout(context.Background(), 3)
defer cancel() // cancel when we are finished consuming integers
gen(ctx)
}