Search code examples
httpgogoroutinego-http

While using a single http client for several goroutines, does editing the transport on one thread affect the other?


Lets say I have a global net/http client in my program. Within this program, I have several goroutines making requests with the same global client. E.g.

Golang Pseudocode:

package main

func editTransportAndFetch(c *http.Client) {
    c.Transport = &http.Transport{
        // Make some unique change here
    }
    c.Get("https://www.google.com")
}

func main() {
    client := http.Client
    
    // Spawns 10 processes
    for i := 0; i < 10; i++ {
        go editTransportAndFetch(client)
    }
}

In this pseudocode example, I demonstrate spawning 10 processes of the http.Transport being edited. In the case of this example, the same exact change is being made, so maybe interference isn't much of a concern. However, regardless, if these processes are happening concurrently, will one process updating the global client's transport interfere with the transport that a different process may be using?

My ultimate use case is that I would like to have a global client and be able to specify a custom DialTLSContext but only for certain requests. Requests that I don't want using the DialTLSContext may be running concurrently as well. I'm worried that if I edit the http.Transport of the client of one request that it may interfere and cause another request to also use DialTLSContext even though I don't want it to.


Solution

  • If you share the same client instance among multiple goroutines and if you modify that client from one of them, the behavior is undefined because it is a data race.

    If you want to modify the client for some of the goroutines, there's no need to use a single client, and you can create a new client for every goroutine.

    If you want to configure one client in main, and use that as a template for all goroutines, pass the client by value, not *client, so a copy of that template is passed to each goroutine, and each goroutine would work on its own copy, sharing the common Transport underneath. If you set the Transport to something else, then since the Client is a copy, it is still safe.

    If you however modify something in the Transport instance (which is a RoundTripper), that is again a race condition. Don't do that.