Reusing context.WithTimeout in deferred function

The below code snippet from MongoDB’s Go quickstart blog post creates context.WithTimeout at the time of connecting with the database and reuses the same for the deferred Disconnect function, which I think is buggy.

func main() {
    client, err := mongo.NewClient(options.Client().ApplyURI("<ATLAS_URI_HERE>"))
    if err != nil {
    ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
    err = client.Connect(ctx)
    if err != nil {
    defer client.Disconnect(ctx)

My train of thought-

context.WithTimeout sets a deadline in UNIX time at the point it is created.
So, passing it to Connect makes sense as we want to cancel the process of establishing the connection if it exceeds the time limit (ie, the derived UNIX time).

Now, passing the same ctx to the deferred Disconnect, which will most probably be called late in the future, will result in the ctx‘s time being in the past. Meaning, it is already expired when the function starts executing. This is not what is expected and breaks the logic as- quoting the doc for Disconnect

If the context expires via cancellation,
deadline, or timeout before the in use connections have returned, the in use
connections will be closed, resulting in the failure of any in flight read
or write operations.

Please tell me if and how I am wrong and/or missing something.

>Solution :

Your understanding is correct.

In the example it is sufficient because the example just connects to the database, performs some example operation (e.g. lists databases), then main() ends, so running the deferred disconnect with the same context will cause no trouble (the example will/should run well under 10 seconds).

In "real-world" applications this won’t be the case of course. So you will likely not use the same context for connecting and disconnecting (unless that context has no timeout).

Leave a Reply