[GODRIVER-1734] Fix txnNumber addition for retryable writes Created: 30/Aug/20  Updated: 28/Oct/23  Resolved: 16/Sep/20

Status: Closed
Project: Go Driver
Component/s: API
Affects Version/s: 1.4.0, 1.3.7
Fix Version/s: 1.4.2

Type: Bug Priority: Major - P3
Reporter: Matt Hartstonge Assignee: Isabella Siu (Inactive)
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Linux, Mongo 3.X/4.X


Backwards Compatibility: Fully Compatible

 Description   

Actual:

Standalone servers support sessions, but the driver errors if a retryable write is done in an explicit session because we add a txnNumber field. We should only add the txnNumber for replica sets and sharded clusters.

 

Original:

Coming from the mgo community driver, I have discovered sessions in the mongo-go-driver rely on 'server sessions'. As an application developer, I am forced to now know what mongo topology the end user is running, with no apparent way to do so, in order to detect if server sessions can be used or not.

It would be preferable if sessions become a no-op if a single mongo is used instead of getting what will appear to most users as an unrelated error due to the advent of multi-document transactions:

"Transaction numbers are only allowed on a replica set member or mongos"

I only discovered this was an issue in a library I have created after migrating to mongo-driver once I had control over the session/context via v1.4.0. This is also somewhat related to mongo version/feature detection for enabling transactions: GODRIVER-1732

 

This localhost repro shows the failure when running on a single mongo:

package main
 
import (
   "context"
 
   log "github.com/sirupsen/logrus"
   "go.mongodb.org/mongo-driver/mongo"
)
 
type Bar struct {
   Name   string
   Type   string
   Rating int
}
 
func main() {
   ctx := context.Background()
   client, err := mongo.Connect(ctx)
   if err != nil {
      log.WithError(err).Fatal("Unable to build mongo connection!")
   }
 
   sess, _ := client.StartSession()
   err = mongo.WithSession(ctx, sess, func(ctx mongo.SessionContext) error {
      // check connection works as mongo-go lazily connects.
      err = client.Ping(ctx, nil)
      if err != nil {
         log.WithError(err).Error("Unable to connect to mongo! Have you configured your connection properly?")
         return err
      }
 
      bar := Bar{
         Name:   "Moro Bar",
         Type:   "Chocolate",
         Rating: 10,
      }
      res, err := client.Database("foo").Collection("bar").InsertOne(ctx, bar)
      if err != nil {
         log.WithError(err).Fatal("unable to insert a foobar")
         return err
      }
 
      log.WithField("id", res.InsertedID).Info("inserted bar")
 
      return nil
   })
   if err != nil {
      log.WithError(err).Fatal("unable to insert a fooMorobar")
   }
}

 

 

The mongo-driver paradigm will throw people off  migrating from mgo.  At the minimum it should be documented that mongo sessions require a replica set.



 Comments   
Comment by Githook User [ 16/Sep/20 ]

Author:

{'name': 'Isabella Siu', 'email': 'isabella.siu@mongodb.com', 'username': 'iwysiu'}

Message: GODRIVER-1734 Fix txnNumber addition for retryable writes (#497)
Branch: release/1.4
https://github.com/mongodb/mongo-go-driver/commit/c3326fdb9df169772c837b6aad417b5cf95a37d2

Comment by Githook User [ 16/Sep/20 ]

Author:

{'name': 'Isabella Siu', 'email': 'isabella.siu@mongodb.com', 'username': 'iwysiu'}

Message: GODRIVER-1734 Fix txnNumber addition for retryable writes (#497)
Branch: master
https://github.com/mongodb/mongo-go-driver/commit/51e3de61f04616a2d97d7c0d9c8758d96b4e52c7

Comment by Matt Hartstonge [ 02/Sep/20 ]

Hi Isabella,

If it helps, I ended up working around this by using a boolean gate by detecting `replSet` status by issuing an admin command: https://github.com/matthewhartstonge/mongo-features/blob/main/features.go#L93-L116

 

Comment by Isabella Siu (Inactive) [ 02/Sep/20 ]

Hi matt.hartstonge@gmail.com,

I'm glad that you were able to solve your problem! While you are correct that mgo's session is like the driver's client, there still shouldn't be an error for using our sessions with standalones, and this ticket will be used to track that work

Comment by Matt Hartstonge [ 31/Aug/20 ]

Sorry, this should be a feature rather than a bug.
The very first concept you are introduced to with the mgo driver is sessions (https://godoc.org/gopkg.in/mgo.v2). I managed to find and understand what a 'server session' was after creating this ticket.

Comment by Matt Hartstonge [ 30/Aug/20 ]

Link to "Convert a Standalone to a Replica Set" in mongo docs: https://docs.mongodb.com/manual/tutorial/convert-standalone-to-replica-set/

Comment by Matt Hartstonge [ 30/Aug/20 ]

As a sidenote: this will also impact development for those that want to create mongo storage drivers for applications that have a defined storage interface due to having to code against errors coming back, rather than being able to perform up front detection.

Developers often perform integration tests against a single dockerized mongo, but deploy to a replicaset in production. This hampers Developer Experience, as setting up replica sets is considerably harder (most cloud based ci provide a single mongo as a drop in service for testing against)

Most Go+mongo web APIs were generally advised to use a mgo session for each API handler, so I suspect it may be widely used.

Generated at Thu Feb 08 08:37:01 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.