-3
    package main

import (
    "context"
    "errors"
    "fmt"
    "time"
)

type result struct {
    record interface{}
    err    error
}

func longRun() {
    for i := 0; ; i++ {
        time.Sleep(1 * time.Second)
        fmt.Println("This is very long running ", i)
    }
}

func process() (interface{}, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    quit := make(chan int)

    go func() {
        for {
            select {
            case <-quit:
                fmt.Println("quit")
                return
            default:
                longRun()
                return
            }
        }
    }()

    select {
    case <-ctx.Done():
        close(quit)
        return nil, errors.New("Execution canceled")
    }
}

func main() {
    value, err := process()
    fmt.Println("value", value)
    fmt.Println("err", err)

    //prevent main function termination
    for i := 0; ; i++ {
    }
}

On timeout the goroutine in process() function terminates but how do i terminate the function longrun().

sample output

This is very long running  0
This is very long running  1
value <nil>
err Execution canceled
This is very long running  2
This is very long running  3
This is very long running  4

As output suggests longrun() function is still executing even after the process function has returned.

How do i terminate longrun() execution immediately after process() function is returned

Sonu Sharma
  • 304
  • 4
  • 13

1 Answers1

1

There is no way to immediately terminate a goroutine. You can use a context to send a cancel notification to the goroutine, but the goroutine has to periodically check the context and terminate if the context is canceled. You may wait for the long-running goroutine to terminate before returning from a function using another channel:

func longRunning(ctx context.Context,done chan struct{}) {
defer close(done)
for {
  ...
  select {
     case <-ctx.Done():
        return
     default:
  }
 }
}

...
ctx, cancel:=context.WithCancel(context.Background())
defer cancel()
ch:=make(chan struct{})
go longRunning(ctx,ch)
// Do things
cancel() // Stop goroutine
// wait for the long running to terminate
<-ch
Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
  • will it be possible to use panic() statement some how to terminate the longrun() function and recover() with user defined error. Since it is important that longrun() function do not do any changes after ctx has timedout – Sonu Sharma May 19 '20 at 18:06
  • 1
    Using panic for flow control is not recommended. Use select with default before making changes and return. – Burak Serdar May 19 '20 at 18:08
  • Just in case, I think it would be fair to note *do not close a channel from the receiver side*. One might accidentally adapt this **as-is**! – BentCoder Mar 22 '21 at 17:42