title: What's the best practice to synchronise channels and wait groups?
body: <p>What's the best practice to synchronise wait groups and channels? I want to handle messages and block on a loop, and it appears that delegating the closing of the channel to another go routine seems to be a weird solution?</p>
  
  <pre><code>func Crawl(url string, depth int, fetcher Fetcher) {
      ch := make(chan string)
  
      var waitGroup sync.WaitGroup
      waitGroup.Add(1)
      go crawlTask(&amp;waitGroup, ch, url, depth, fetcher)
  
      go func() {
          waitGroup.Wait()
          close(ch)
      }()
  
      for message := range ch {
          // I want to handle the messages here
          fmt.Println(message)
      }
  }
  
  func crawlTask(waitGroup *sync.WaitGroup, ch chan string, url string, depth int, fetcher Fetcher) {
      defer waitGroup.Done()
  
      if depth &lt;= 0 {
          return
      }
      body, urls, err := fetcher.Fetch(url)
  
      if err != nil {
          ch &lt;- err.Error()
          return
      }
      ch &lt;- fmt.Sprintf("found: %s %q\n", url, body)
      for _, u := range urls {
          waitGroup.Add(1)
          go crawlTask(waitGroup, ch, u, depth-1, fetcher)
      }
  }
  func main() {
      Crawl("http://golang.org/", 4, fetcher)
  }
  
  // truncated from https://tour.golang.org/concurrency/10 webCrawler
  </code></pre>