title: Go GRPC client disconnect terminates Go server
body: <p>Bit of a newb to both Go and GRPC, so bear with me.</p>
  <p>Using go version go1.14.4 windows/amd64, proto3, and latest grpc (1.31 i think).  I'm trying to set up a bidi streaming connection that will likely be open for longer periods of time.  Everything works locally, except if I terminate the client (or one of them) it kills the server as well with the following error:</p>
  <blockquote>
  <p>Unable to trade data rpc error: code = Canceled desc = context canceled</p>
  </blockquote>
  <p>This error comes out of this code server side</p>
  <pre><code>func (s *exchangeserver) Trade(stream proto.ExchageService_TradeServer) error {
  
      endchan := make(chan int)
      defer close(endchan)
  
      go func() {
          for {
              req, err := stream.Recv()
              if err == io.EOF {
                  break
              }
              if err != nil {
                  log.Fatal(&quot;Unable to trade data &quot;, err)
                  break
              }
  
              fmt.Println(&quot;Got &quot;, req.GetNumber())
          }
  
          endchan &lt;- 1
      }()
  
      go func() {
          for {
              resp := &amp;proto.WordResponse{Word: &quot;Hello again &quot;}
              err := stream.Send(resp)
              if err != nil {
                  log.Fatal(&quot;Unable to send from server &quot;, err)
                  break
              }
  
              time.Sleep(time.Duration(500 * time.Millisecond))
          }
  
          endchan &lt;- 1
      }()
  
      &lt;-endchan
      return nil
  }
  </code></pre>
  <p>And the Trade() RPC is so simple it isn't worth posting the .proto.
  The error is clearly coming out of the Recv() call, but that call blocks until it sees a message, like the client disconnect, at which point I would expect it to kill the stream, not the whole process.  I've tried adding a service handler with HandleConn(context, stats.ConnStats) and it does catch the disconnect before the server dies, but I can't do anything with it.  I've even tried creating a global channel that the serve handler pushes a value into when HandleRPC(context, stats.RPCStats) is called and only allowing Recv() to be called when there's a value in the channel, but that can't be right, that's like blocking a blocking function for safety and it didn't work anyway.</p>
  <p>This has to be one of those real stupid mistakes that beginner's make.  Of what use would GPRC be if it couldn't handle a client disconnect without dying?  Yet I have read probably a trillion (ish) posts from every corner of the internet and noone else is having this issue.  On the contrary, the more popular version of this question is &quot;My client stream stays open after disconnect&quot;.  I'd expect that issue.  Not this one.</p>