Skip to content

Commit d68b09b

Browse files
author
Divjot Arora
committed
GODRIVER-1655 retry replSetStepDown for LockTimeout errors
1 parent 056c274 commit d68b09b

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

mongo/integration/crud_helpers_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
var (
3232
emptyDoc = []byte{5, 0, 0, 0, 0}
3333
errorCommandNotFound int32 = 59
34+
errorLockTimeout int32 = 24
3435
killAllSessionsErrorCodes = map[int32]struct{}{
3536
errorInterrupted: {},
3637
errorCommandNotFound: {}, // the killAllSessions command does not exist on server versions < 3.6
@@ -1406,12 +1407,38 @@ func executeAdminCommand(mt *mtest.T, op *operation) {
14061407
_ = client.Disconnect(mtest.Background)
14071408
}()
14081409

1409-
db := client.Database("admin")
14101410
cmd := op.Arguments.Lookup("command").Document()
1411+
if op.CommandName == "replSetStepDown" {
1412+
// replSetStepDown can fail with transient errors, so we use executeAdminCommandWithRetry to handle them and
1413+
// retry until a timeout is hit.
1414+
executeAdminCommandWithRetry(mt, client, cmd)
1415+
return
1416+
}
1417+
1418+
db := client.Database("admin")
14111419
err = db.RunCommand(mtest.Background, cmd).Err()
14121420
assert.Nil(mt, err, "RunCommand error for command %q: %v", op.CommandName, err)
14131421
}
14141422

1423+
func executeAdminCommandWithRetry(mt *mtest.T, client *mongo.Client, cmd interface{}, opts ...*options.RunCmdOptions) {
1424+
mt.Helper()
1425+
1426+
ctx, cancel := context.WithTimeout(mtest.Background, 10*time.Second)
1427+
defer cancel()
1428+
1429+
for {
1430+
err := client.Database("admin").RunCommand(ctx, cmd, opts...).Err()
1431+
if err == nil {
1432+
return
1433+
}
1434+
1435+
if ce, ok := err.(mongo.CommandError); ok && ce.Code == errorLockTimeout {
1436+
continue
1437+
}
1438+
mt.Fatalf("error executing command: %v", err)
1439+
}
1440+
}
1441+
14151442
// verification function to use for all count operations
14161443
func verifyCountResult(mt *mtest.T, actualResult int64, expectedResult interface{}) {
14171444
mt.Helper()

mongo/integration/primary_stepdown_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"go.mongodb.org/mongo-driver/mongo"
1616
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
1717
"go.mongodb.org/mongo-driver/mongo/options"
18-
"go.mongodb.org/mongo-driver/mongo/readpref"
1918
)
2019

2120
const (
@@ -66,11 +65,14 @@ func TestConnectionsSurvivePrimaryStepDown(t *testing.T) {
6665
defer cur.Close(mtest.Background)
6766
assert.True(mt, cur.Next(mtest.Background), "expected Next true, got false")
6867

69-
err = mt.Client.Database("admin").RunCommand(mtest.Background, bson.D{
68+
// replSetStepDown can fail with transient errors, so we use executeAdminCommandWithRetry to handle them and
69+
// retry until a timeout is hit.
70+
stepDownCmd := bson.D{
7071
{"replSetStepDown", 5},
7172
{"force", true},
72-
}, options.RunCmd().SetReadPreference(readpref.Primary())).Err()
73-
assert.Nil(mt, err, "replSetStepDown error: %v", err)
73+
}
74+
stepDownOpts := options.RunCmd().SetReadPreference(mtest.PrimaryRp)
75+
executeAdminCommandWithRetry(mt, mt.Client, stepDownCmd, stepDownOpts)
7476

7577
assert.True(mt, cur.Next(mtest.Background), "expected Next true, got false")
7678
assert.False(mt, isPoolCleared(), "expected pool to not be cleared but was")

0 commit comments

Comments
 (0)