title: Why is my Golang Channel Write Blocking Forever?
body: <p>I've been attempting to take a swing at concurrency in Golang by refactoring one of my command-line utilities over the past few days, but I'm stuck.</p>
  
  <p><a href="https://github.com/stephendolan/jira_open_comment_emailer" rel="noreferrer">Here's</a> the original code (master branch).</p>
  
  <p><a href="https://github.com/stephendolan/jira_open_comment_emailer/tree/x_concurrent" rel="noreferrer">Here's</a> the branch with concurrency (x_concurrent branch).</p>
  
  <p>When I execute the concurrent code with <code>go run jira_open_comment_emailer.go</code>, the <code>defer wg.Done()</code> never executes if the JIRA issue is added to the channel <a href="https://github.com/stephendolan/jira_open_comment_emailer/blob/x_concurrent/jira_open_comment_emailer.go#L241" rel="noreferrer">here</a>, which causes my <code>wg.Wait()</code> to hang forever.</p>
  
  <p>The idea is that I have a large amount of JIRA issues, and I want to spin off a goroutine for each one to see if it has a comment I need to respond to. If it does, I want to add it to some structure (I chose a channel after some research) that I can read from like a queue later to build up an email reminder.</p>
  
  <p>Here's the relevant section of the code:</p>
  
  
  
  <pre><code>// Given an issue, determine if it has an open comment
  // Returns true if there is an open comment on the issue, otherwise false
  func getAndProcessComments(issue Issue, channel chan&lt;- Issue, wg *sync.WaitGroup) {
      // Decrement the wait counter when the function returns
      defer wg.Done()
  
      needsReply := false
  
      // Loop over the comments in the issue
      for _, comment := range issue.Fields.Comment.Comments {
          commentMatched, err := regexp.MatchString("~"+config.JIRAUsername, comment.Body)
          checkError("Failed to regex match against comment body", err)
  
          if commentMatched {
              needsReply = true
          }
  
          if comment.Author.Name == config.JIRAUsername {
              needsReply = false
          }
      }
  
      // Only add the issue to the channel if it needs a reply
      if needsReply == true {
          // This never allows the defered wg.Done() to execute?
          channel &lt;- issue
      }
  }
  
  func main() {
      start := time.Now()
  
      // This retrieves all issues in a search from JIRA
      allIssues := getFullIssueList()
  
      // Initialize a wait group
      var wg sync.WaitGroup
  
      // Set the number of waits to the number of issues to process
      wg.Add(len(allIssues))
  
      // Create a channel to store issues that need a reply
      channel := make(chan Issue)
  
      for _, issue := range allIssues {
          go getAndProcessComments(issue, channel, &amp;wg)
      }
  
      // Block until all of my goroutines have processed their issues.
      wg.Wait()
  
      // Only send an email if the channel has one or more issues
      if len(channel) &gt; 0 {
          sendEmail(channel)
      }
  
      fmt.Printf("Script ran in %s", time.Since(start))
  }
  </code></pre>