Depends on how quickly you want the expensive operation to terminate. Unless it is cpu bound the expensive operation probably is making IO calls - pass the context to those so the cancel will propagate. If it doesn’t I think a periodic poll/check of the context is simpler.
> On Jan 8, 2021, at 9:17 PM, Amit Saha <amitsaha...@gmail.com> wrote: > > > >> On 8 Jan 2021, at 1:59 pm, Robert Engels <reng...@ix.netcom.com> wrote: >> >> You need to pass the context to the expensive work a periodically check if >> it has been cancelled. > > Thanks. I was thinking how to implement this. Is this a nice way to do it? > > func clientDisconnected(ctx context.Context, done chan bool) bool { > select { > case <-done: > return false > case <-ctx.Done(): > log.Printf("api: client disconnected.") > return true > } > } > > > func apiHandlerFunction(w http.ResponseWriter, r *http.Request) { > done := make(chan bool) > go func() { > log.Println("First expensive operation") > time.Sleep(5 * time.Second) > done <- true > }() > > if clientDisconnected(r.Context(), done) { > return > } > > go func() { > log.Println("Second expensive operation") > time.Sleep(5 * time.Second) > done <- true > }() > > if clientDisconnected(r.Context(), done) { > return > } > > fmt.Fprintf(w, "All operations done") > } > >> >>>> On Jan 7, 2021, at 8:55 PM, Amit Saha <amitsaha...@gmail.com> wrote: >>> >>> Hi all, I want to confirm whether my understanding related to handling >>> HTTP client disconnections is correct or not. >>> >>> Consider this: >>> >>> func longRunningProcessing(ctx context.Context, w http.ResponseWriter) { >>> done := make(chan bool) >>> go func() { >>> expensiveWork() # This is a blocking expensive processing call >>> done <- true >>> }() >>> select { >>> case <-ctx.Done(): >>> log.Printf("Client disconnected. Cancelling expensive operation.") >>> return >>> case <- done: >>> fmt.Fprintf(w, "Done!") >>> } >>> } >>> >>> func apiHandler(w http.ResponseWriter, r *http.Request) { >>> ctx := r.Context() >>> longRunningProcessing(ctx) >>> } >>> >>> When a client connection close is detected, the Done() call in select >>> unblocks and the call goes out of the longRunningProcessing() >>> function. >>> However, the goroutine with the expensiveWork() is actually still running? >>> >>> It seems like there is *no* way there is *not* going to be a goroutine >>> leak (and resources associated with it) in a pattern like the above >>> unless >>> I have control over expensiveWork() and can instrument it with a child >>> context. I am also thinking if there is a way to obtain the behavior >>> similar to exec.CommandContext() command >>> which does a hard kill of the external process when the context is >>> cancelled. >>> >>> Thanks for any insights and clarifications. >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "golang-nuts" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to golang-nuts+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/CANODV3k9gF0gLWB1Z1OGaH-ArPbq8mNPKx9mzrTOTCa-kZZmvg%40mail.gmail.com. >> > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1F6B0741-5598-4705-B017-007D85A3719C%40ix.netcom.com.