Performance implication of (mongo.Client).Ping

Hi everyone,

I’ve recently noticed some odd behavior while testing the performance of writing or reading to a serveless cluster.

I don’t think is related to the serverless option, but as a context I’m using a new Serverless cluster in AWS (Ireland region) which I interact with from my local machine.

The code I’m using is:

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type (
	Item struct {
		Value string `bson:"value"`
	}
)

func main() {
	ctx := context.Background()
	client, err := mongo.Connect(ctx, options.Client().ApplyURI("add-url"))
	if err != nil {
		log.Fatalln(err)
	}

	err = client.Ping(ctx, nil)
	if err != nil {
		log.Fatalln(err)
	}

	collection := client.Database("test").Collection("test")
	item := Item{
		Value: "foo",
	}
	start := time.Now()
	_, err = collection.InsertOne(ctx, item)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Println("Item added in", time.Since(start))
}

This works fine, producing results of about 60ms consistently.

However, if I remove err = client.Ping(ctx, nil) the times jump to over 500ms consistently. Why does this happen?

@lewislbr thanks for the question! I think the difference in duration between the two scenarios comes from the extra time it takes to establish a new connection to the Serverless cluster for the first operation.

After creating a new mongo.Client, the first operation has to establish a new connection to a server. When you run a Ping before running InsertOne, a new connection is established to run the Ping and reused to run the InsertOne. When you run an InsertOne without running a Ping, a new connection has to be established to run the InsertOne.

If you run your InsertOne operation in a loop, you should see the first operation take longer because it has to establish a new connection and the subsequent operations don’t take as long because they can reuse that connection.

E.g. loop code:

for i := 0; i < 10; i++ {
	start := time.Now()
	_, err = collection.InsertOne(ctx, item)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Println("Item added in", time.Since(start))
}

That makes a lot of sense and I understand why now. Thanks a lot @Matt_Dale !