title: What is the right way to safely finish goroutines in my code?
body: <p>I am writing a simple tcp server, the goroutine model is very straight forward: </p>
  
  <p>One goroutine is responsible for accepting new connections; for every new connection, three goroutines are started :</p>
  
  <ol>
  <li>one for read</li>
  <li>one for process and handle application logic</li>
  <li>one for write </li>
  </ol>
  
  <p>Currently one server will serve no more than 1000 users, so I don't try to limit goroutine numbers.</p>
  
  <pre><code>for {
      conn, err := listener.Accept()
      // ....
      connHandler := connHandler{
          conn:      conn,
          done:      make(chan struct{}),
          readChan:  make(chan string, 100),
          writeChan: make(chan string, 100),
      }
      // ....
      go connHandler.readAll()    
      go connHandler.processAll() 
      go connHandler.writeAll()   
  }
  </code></pre>
  
  <p>I use the <code>done</code> channel to notify all three channels to finish, when user logout or a permanent network error happened, <code>done</code> channel will be closed (use sync.Once to make sure closing only happen once):</p>
  
  <pre><code>func (connHandler *connHandler) Close() {
      connHandler.doOnce.Do(func() {
          connHandler.isClosed = true
          close(connHandler.done)
      })
  }
  </code></pre>
  
  <p>Below is the code of <code>writeAll()</code> method:</p>
  
  <pre><code>func (connHandler *connHandler) writeAll() {
      writer := bufio.NewWriter(connHandler.conn)
  
      for {
          select {
          case &lt;-connHandler.done:
              connHandler.conn.Close()
              return
          case msg := &lt;-connHandler.writeChan:
              connHandler.writeOne(msg, writer)
          }
      }
  }
  </code></pre>
  
  <p>There is a <code>Send</code> method to send message to a user, by sending strings to the write channel:</p>
  
  <pre><code>func (connHandler *connHandler) Send(msg string) {
      case connHandler.writeChan &lt;- msg:
  }
  </code></pre>
  
  <p>The <code>Send</code> method will be called mainly in <code>processAll()</code> goroutine, but also in many other goroutines because different users need to communicate with each other.</p>
  
  <p>Now is the problem: if userA logout or network failed, userB send a message to userA, userB's goroutine may be permanently blocked because no one will ever receive the message from the channel.</p>
  
  <p><strong>My solution:</strong></p>
  
  <p>My first thought is to use a boolean value to make sure connHanler is not closed when sending to it:</p>
  
  <pre><code>func (connHandler *connHandler) Send(msg string) {
      if !connHandler.isClosed {
          connHandler.writeChan &lt;- msg
      }
  }
  </code></pre>
  
  <p>But I think <code>connHandler.writeChan &lt;- msg</code> and <code>close(done)</code> can still happen at the same time, the possibility of blocking still exist. So I have to add a timeout:</p>
  
  <pre><code>func (connHandler *connHandler) Send(msg string) {
      if !connHandler.isClosed {
          timer := time.NewTimer(10 * time.Second)
          defer timer.Stop()
          select {
          case connHandler.writeChan &lt;- msg:
          case &lt;-timer.C:
              log.Warning(connHandler.Addr() + " send msg timeout:" + msg)
          }
      }
  
  }
  </code></pre>
  
  <p>Now I feel the code is safe, but also ugly, and start a timer every time when sending a message feels like an unnecessary overhead.</p>
  
  <p>Then I read this article:  <a href="https://go101.org/article/channel-closing.html" rel="noreferrer">https://go101.org/article/channel-closing.html</a>, My problem looks like the second example in the article: </p>
  
  <blockquote>
    <p>One receiver, N senders, the receiver says "please stop sending more"
    by closing an additional signal channel</p>
  </blockquote>
  
  <p>But I think this solution can't eliminate the possibility of blocking in my circumstance.</p>
  
  <p>Maybe the easiest solution is to just close the write channel and let the <code>Send</code> method panic, then use <code>recover</code> to handle the panic? But this looks like an ugly way, too.</p>
  
  <p>So is there a simple and straight forward way to accomplish what I want to do?</p>
  
  <p>(My English is not good, so if there is any ambiguity, please point out, thanks.)</p>