title: Passing context from gRPC endpoint to goroutine receives context canceled error
body: <p>I'm attempting to pass the context from an incoming gRPC endpoint to a goroutine which is responsible for sending another request to an external service, but I'm receiving <code>Error occurred: context canceled</code> from the <code>ctxhttp.Get</code> function call within the goroutine:</p>
  
  <pre><code>package main
  
  import (
    "fmt"
    "net"
    "net/http"
    "os"
    "sync"
  
    "golang.org/x/net/context/ctxhttp"
  
    dummy_service "github.com/myorg/testing-apps/dummy-proto/gogenproto/dummy/service"
    "github.com/myorg/testing-apps/dummy-proto/gogenproto/dummy/service/status"
    "golang.org/x/net/context"
  
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
  )
  
  func main() {
    var err error
  
    grpcServer := grpc.NewServer()
  
    server := NewServer()
    dummy_service.RegisterDummyServer(grpcServer, server)
    reflection.Register(grpcServer)
  
    lis, err := net.Listen("tcp", ":9020")
    if err != nil {
      fmt.Printf("Failed to listen: %+v", err)
      os.Exit(-1)
    }
    defer lis.Close()
  
    wg := sync.WaitGroup{}
  
    wg.Add(1)
    go func() {
      defer wg.Done()
      fmt.Println("Starting gRPC Server")
      if err := grpcServer.Serve(lis); err != nil {
        fmt.Printf("Failed to serve gRPC: %+v", err)
        os.Exit(-1)
      }
    }()
  
    wg.Wait()
  }
  
  type server struct{}
  
  func NewServer() server {
    return server{}
  }
  
  func (s server) Status(ctx context.Context, in *status.StatusRequest) (*status.StatusResponse, error) {
    go func(ctx context.Context) {
      client := http.Client{}
  
      // it's important to send the ctx from the parent function here because it contains
      // a correlation-id which was inserted using grpc middleware, and the external service
      // prints this value in the logs to tie everything together
      if _, err := ctxhttp.Get(ctx, &amp;client, "http://localhost:4567"); err != nil {
        fmt.Println("Error encountered:", err)
        return
      }
  
      fmt.Println("No error encountered")
    }(ctx)
  
    response := status.StatusResponse{
      Status: status.StatusResponse_SUCCESS,
    }
  
  
    // if I enable the following, everything works, and I get "No error encountered"
    // time.Sleep(10 * time.Millisecond)
  
    return &amp;response, nil
  }
  </code></pre>
  
  <p>If I add a <code>time.Sleep()</code> inside the calling function, the goroutine succeeds as expected and doesn't receive any error. It seems that the context of the parent function becomes canceled as soon as it returns, and since the parent is ending before the goroutine, the context passed to the goroutine is receiving the <code>context canceled</code> error.</p>
  
  <p>I realize I could solve this by having the calling function wait for the goroutine to finish, which would prevent the context from being canceled, but I don't want to do this since I want the function to return immediately so that the client hitting the endpoint gets a response as soon as possible, while the goroutine continues processing in the background.</p>
  
  <p>I can also solve this by not using the passed in <code>ctx</code> and instead using <code>context.Background()</code> in my goroutine, however, I want to use the incoming <code>ctx</code> because it contains a <code>correlation-id</code> value which was inserted by grpc middleware and needs to be passed along as part of the outgoing request that the goroutine makes, so that the next server can print this <code>correlation-id</code> in its log messages to tie the requests together.</p>
  
  <p>I've ended up solving the issue by extracting the <code>correlation-id</code> from the incoming context and inserting it into a new <code>context.Background()</code> in the goroutine, but I wanted to avoid this since it adds a bunch of boilerplate code around every outgoing request that a goroutine makes, instead of just being able to pass along the context.</p>
  
  <p>Can anyone explain to me exactly why the context is getting canceled and let me know if there's a "best practices" solution for this type of situation?  Is it not possible to use the context passed in from the calling function in a goroutine with gRPC?</p>