title: Do goroutines with receiving channel as parameter stop, when the channel is closed?
body: <p>I have been reading "Building microservices with go" and the book introduces <a href="https://github.com/eapache/go-resiliency/tree/master/deadline" rel="nofollow noreferrer"><code>apache/go-resiliency/deadline</code></a> package for handling timeouts.</p>
  
  <p><code>deadline.go</code></p>
  
  <pre><code>// Package deadline implements the deadline (also known as "timeout") resiliency pattern for Go.
  package deadline
  
  import (
      "errors"
      "time"
  )
  
  // ErrTimedOut is the error returned from Run when the deadline expires.
  var ErrTimedOut = errors.New("timed out waiting for function to finish")
  
  // Deadline implements the deadline/timeout resiliency pattern.
  type Deadline struct {
      timeout time.Duration
  }
  
  // New constructs a new Deadline with the given timeout.
  func New(timeout time.Duration) *Deadline {
      return &amp;Deadline{
          timeout: timeout,
      }
  }
  
  // Run runs the given function, passing it a stopper channel. If the deadline passes before
  // the function finishes executing, Run returns ErrTimeOut to the caller and closes the stopper
  // channel so that the work function can attempt to exit gracefully. It does not (and cannot)
  // simply kill the running function, so if it doesn't respect the stopper channel then it may
  // keep running after the deadline passes. If the function finishes before the deadline, then
  // the return value of the function is returned from Run.
  func (d *Deadline) Run(work func(&lt;-chan struct{}) error) error {
      result := make(chan error)
      stopper := make(chan struct{})
  
      go func() {
          result &lt;- work(stopper)
      }()
  
      select {
      case ret := &lt;-result:
          return ret
      case &lt;-time.After(d.timeout):
          close(stopper)
          return ErrTimedOut
      }
  }
  </code></pre>
  
  <p><code>deadline_test.go</code></p>
  
  <pre><code>package deadline
  
  import (
      "errors"
      "testing"
      "time"
  )
  
  func takesFiveMillis(stopper &lt;-chan struct{}) error {
      time.Sleep(5 * time.Millisecond)
      return nil
  }
  
  func takesTwentyMillis(stopper &lt;-chan struct{}) error {
      time.Sleep(20 * time.Millisecond)
      return nil
  }
  
  func returnsError(stopper &lt;-chan struct{}) error {
      return errors.New("foo")
  }
  
  func TestDeadline(t *testing.T) {
      dl := New(10 * time.Millisecond)
  
      if err := dl.Run(takesFiveMillis); err != nil {
          t.Error(err)
      }
  
      if err := dl.Run(takesTwentyMillis); err != ErrTimedOut {
          t.Error(err)
      }
  
      if err := dl.Run(returnsError); err.Error() != "foo" {
          t.Error(err)
      }
  
      done := make(chan struct{})
      err := dl.Run(func(stopper &lt;-chan struct{}) error {
          &lt;-stopper
          close(done)
          return nil
      })
      if err != ErrTimedOut {
          t.Error(err)
      }
      &lt;-done
  }
  
  func ExampleDeadline() {
      dl := New(1 * time.Second)
  
      err := dl.Run(func(stopper &lt;-chan struct{}) error {
          // do something possibly slow
          // check stopper function and give up if timed out
          return nil
      })
  
      switch err {
      case ErrTimedOut:
          // execution took too long, oops
      default:
          // some other error
      }
  }
  </code></pre>
  
  <h2>1st question</h2>
  
  <pre><code>// in deadline_test.go
  if err := dl.Run(takesTwentyMillis); err != ErrTimedOut {
      t.Error(err)
  }  
  </code></pre>
  
  <p>I have problem understanding the execution flow of above code. As far as I understand, because the <code>takesTwentyMillis</code> function sleeps longer than the set timeout duration of 10 milliseconds,</p>
  
  <pre><code>// in deadline.go
  case &lt;-time.After(d.timeout):
      close(stopper)
      return ErrTimedOut
  </code></pre>
  
  <p>time.After emits current time, and this case is selected. Then the stopper channel is closed and ErrTimeout is returned.</p>
  
  <p>What I do not understand is, <strong><em>what closing the stopper channel does to the anonymous goroutine that might  still be running</em></strong>
  I think, when the stopper channel is closed, the below goroutine might still be running.</p>
  
  <pre><code>go func() {
          result &lt;- work(stopper)
      }()
  </code></pre>
  
  <p>(Please correct me if I'm wrong here) I think after <code>close(stopper)</code>, this goroutine will call <code>takesTwentyMillis</code>(=work function) with stopper channel as its parameter. And the function will proceed and sleep for 20 milliseconds and return nil to pass to result channel. And the main() ends here, right?</p>
  
  <p>I do not see what is the point of closing the stopper channel here. The <code>takesTwentyMillis</code> function does not seem to use the channel within the function body anyway :(.</p>
  
  <h2>2nd question</h2>
  
  <pre><code>// in deadline_test.go within TestDeadline()
  done := make(chan struct{})
  err := dl.Run(func(stopper &lt;-chan struct{}) error {
      &lt;-stopper
      close(done)
      return nil
  })
  if err != ErrTimedOut {
      t.Error(err)
  }
  &lt;-done
  </code></pre>
  
  <p>This is the part I do not understand completely. I think when <code>dl.Run</code> is run, stopper channel is initialized. But because there is no value in the stopper channel, the function call will be blocked at <code>&lt;-stopper</code>...but because I do not understand this code, I do not see why this code exists in the first place (i.e. what this code is trying to test, and how it is executed, etc).</p>
  
  <hr>
  
  <h2>3rd(additional) question regarding the 2nd question</h2>
  
  <p>So I understand that when <code>Run</code> function in the 2nd question triggers the stopper channel to close, the worker function gets the signal. And the worker closes the done channel and returns nil.
  I used delve(=go debugger) to see this, and the gdb takes me to the goroutine in <code>deadline.go</code> after the line <code>return nil</code>. </p>
  
  <pre><code>   err := dl.Run(func(stopper &lt;-chan struct{}) error {
          &lt;-stopper
          close(done)
  --&gt;     return nil   
      })
  </code></pre>
  
  <p>After typing n for stepping over to the next line, delve takes me here</p>
  
  <pre><code>    go func() {
  --&gt;             result &lt;- work(stopper)
              }()
  </code></pre>
  
  <p>And the process kind of finishes here because when I type n again the command line prompts PASS and process exits. Why does the process finishes here? The <code>work(stopper)</code> seems to return <code>nil</code>, which should then be passed to result channel right? But this line does not seem to execute for some reason.</p>
  
  <p>I know the main goroutine, which is the <code>Run</code> function, has already returned ErrTimedOut. So I guess it has something to do with this? </p>