I'm encountering an issue in a Go application that uses the official MongoDB Go driver. We have the use case where a ReplicaSet is recreated from scratch. Replica Set consists of 2 members, no arbiter or non-SRV connection string. Even after the Replica Set is back up and healthy and there are no network issues, the Go app fails to connect/reconnect/rediscover and it appears to get stuck with the following error:
server selection error: context deadline exceeded, current topology: { Type: ReplicaSetNoPrimary, Servers: [] }
I found this thread that seems related:
When a driver has completely lost connection to a replica set, there are two possible circumstances:
- The replica set is still there, but there is some network interruption.
- All replica set nodes have moved to a totally new set of hosts and/or IPs in a short period of time and might be rediscoverable with the connection string.
Drivers could simultaneously attempt to connect to the last known MongoDB replia set and re-initialize using the connection string to see which succeeds first. However, that may not always be the best behavior for all use cases, so we have historically assumed case #1 (the more common case) and required users to implement their own recovery logic for case #2.
It seems that the MongoDB Go driver sticks somehow to a ReplicaSet, and it is not able to rediscover/reconnect if the ReplicaSet changed/was recreated. I haven't found the reason why or find any option to force to reconnect. So far, the only workaround is to restart the app, which I find a bit weird in the cloud world.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
const uri = "mongodb://primary:27017,secondary:27017"
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
clientOptions := options.Client().ApplyURI(uri)
clientOpts.SetReplicaSet("test")
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
defer func() {
if err = client.Disconnect(ctx); err != nil {
log.Fatal(err)
}
fmt.Println("Connection to MongoDB closed.")
}()
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal("Could not connect to MongoDB:", err)
}
fmt.Println("Successfully connected to MongoDB")
collection := client.Database("testdb").Collection("items")
fmt.Println("Collection instance created:", collection.Name())
}
Any idea what could be causing this or recommended patterns to handle it? I suspect that the go driver topology stick to a particular ReplicaSet id unless it is restarted, but I could not find information in this regards.