In this scenario:
Here's my solution. It's works, but doesn't feel elegant or in Go style.
Can you please correct me or show me a better solution?
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx, cancel := context.WithCancel(context.Background())
var (
data int
readCh = make(chan struct{})
)
go func() {
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
readCh <- struct{}{}
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout, cancel)
select {
case <-ctx.Done():
log.Println("cancelled")
return
case <-readCh:
break
}
log.Println("got final data", data)
Close readCh
to indicate that the long running goroutine completed. There are two benefits to closing the channel compared to sending a value:
Here's the updated code:
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx, cancel := context.WithCancel(context.Background())
var (
data int
readCh = make(chan struct{})
)
go func() {
defer close(readCh)
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout, cancel)
select {
case <-ctx.Done():
log.Println("cancelled")
return
case <-readCh:
break
}
log.Println("got final data", data)
If you do not need to distinguish between completion of the long-running goroutine and cancelation, call the cancel function from the goroutine.
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx, cancel := context.WithCancel(context.Background())
var data int
go func() {
defer cancel()
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout, cancel)
<-ctx.Done()
log.Println("got final data", data)