type Response struct {
data interface{}
status bool
}
func Find() (interface{}, bool) {
ch := make(chan Response, 1)
go func() {
data, status := findCicC
If you want to, you can create your own timeout system for arbitrary work by having a single receive operation on the channel (in the main goroutine), and whichever other goroutine reaches its send operation first -- the time.Sleep
or the one doing actual work -- wins.
Here's a complete runnable example/simulation. Adjust timeout and delay values to simulate different scenarios. The channel is unbuffered, and is closed after a single value is read to allow the other goroutine to exit on send.
package main
import(
"fmt"
"time"
)
type Response struct {
Data []byte
Status int
}
func Wait(s int) {
time.Sleep(time.Duration(s) * time.Second)
}
func FindWrapper(ch chan Response, delay int) {
// Put real find stuff here...
// Dummy response after wait for testing purposes
Wait(delay)
ch <- Response{[]byte("Some data..."), 200}
}
func main() {
timeout := 3
delay := 4
ch := make(chan Response)
// whoever sends to ch first wins...
go func() {
Wait(timeout)
ch <- Response{}
}()
go FindWrapper(ch, delay)
r := <-ch
close(ch)
if r.Data == nil {
r.Status = 500 // or whatever you want for timeout status
}
fmt.Printf("Data: %s Status: %d\n", string(r.Data), r.Status)
}
A buffered channel would work too. And you could accomplish the same thing with a sync.WaitGroup
where you only call Add once and then close the channel after wg.Wait()
.
That said, I suggest trying JimB's solution of using a Context
timeout, as it probably works for your use case and is a less complicated solution.
You control cancelation of http requests with a context.Context.
// create a timeout or cancelation context to suit your requirements
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req, err := http.NewRequest("GET", location, nil)
// add the context to each request and they will be canceled in unison
resp, err := http.Do(req.WithContext(ctx))