Uploaded image for project: 'Go Driver'
  1. Go Driver
  2. GODRIVER-1734

Fix txnNumber addition for retryable writes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Fixed
    • Affects Version/s: 1.4.0, 1.3.7
    • Fix Version/s: 1.4.2
    • Component/s: API
    • Security Level: Public
    • Labels:
      None
    • 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.

        Attachments

          Activity

            People

            Assignee:
            isabella.siu Isabella Siu
            Reporter:
            matt.hartstonge@gmail.com Matt Hartstonge
            Participants:
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: