title: Graceful shutdown of gRPC downstream
body: <p>Using the following proto buffer code :</p>
  
  <pre><code>syntax = "proto3";
  
  package pb;
  
  message SimpleRequest {
      int64 number = 1;
  }
  
  message SimpleResponse {
      int64 doubled = 1;
  }
  
  // All the calls in this serivce preform the action of doubling a number.
  // The streams will continuously send the next double, eg. 1, 2, 4, 8, 16.
  service Test {
      // This RPC streams from the server only.
      rpc Downstream(SimpleRequest) returns (stream SimpleResponse);
  }
  </code></pre>
  
  <p>I'm able to successfully open a stream, and continuously get the next doubled number from the server.</p>
  
  <p>My go code for running this looks like :</p>
  
  <pre><code>ctxDownstream, cancel := context.WithCancel(ctx)
  downstream, err := testClient.Downstream(ctxDownstream, &amp;pb.SimpleRequest{Number: 1})
  for {
      responseDownstream, err := downstream.Recv()
      if err != io.EOF {
          println(fmt.Sprintf("downstream response: %d, error: %v", responseDownstream.Doubled, err))
  
          if responseDownstream.Doubled &gt;= 32 {
              break
          }
      }
  }
  cancel() // !!This is not a graceful shutdown
  println(fmt.Sprintf("%v", downstream.Trailer()))
  </code></pre>
  
  <p>The problem I'm having is using a context cancellation means my downstream.Trailer() response is empty. Is there a way to gracefully close this connection from the client side and receive downstream.Trailer().</p>
  
  <p>Note: if I close the downstream connection from the server side, my trailers are populated. But I have no way of instructing my server side to close this particular stream. So there must be a way to gracefully close a stream client side.</p>
  
  <p>Thanks.</p>
  
  <p>As requested some server code : </p>
  
  <pre><code>func (b *binding) Downstream(req *pb.SimpleRequest, stream pb.Test_DownstreamServer) error {
      request := req
  
      r := make(chan *pb.SimpleResponse)
      e := make(chan error)
      ticker := time.NewTicker(200 * time.Millisecond)
      defer func() { ticker.Stop(); close(r); close(e) }()
  
      go func() {
          defer func() { recover() }()
          for {
              select {
              case &lt;-ticker.C:
                  response, err := b.Endpoint(stream.Context(), request)
                  if err != nil {
                      e &lt;- err
                  }
                  r &lt;- response
              }
          }
      }()
  
      for {
          select {
          case err := &lt;-e:
              return err
          case response := &lt;-r:
              if err := stream.Send(response); err != nil {
                  return err
              }
              request.Number = response.Doubled
          case &lt;-stream.Context().Done():
              return nil
          }
      }
  }
  </code></pre>
  
  <p>You will still need to populate the trailer with some information. I use the grpc.StreamServerInterceptor to do this.</p>