Cursors should use client-level timeouts

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • 2.3.1
    • Affects Version/s: None
    • Component/s: None
    • None
    • None
    • Go Drivers
    • Not Needed
    • None
    • None
    • None
    • None
    • None
    • None

      Detailed steps to reproduce the problem?

      According to the CSOT specifications, the timeoutMS value must apply to cursor iteration methods such as cursor.Next():

      When applying the timeoutMS option to next calls on cursor, drivers MUST ensure it applies to the entire call, not individual commands.

      To reproduce:

      func TestClientLevelTimeoutForCursors(t *testing.T) {
      	client, err := mongo.Connect(options.Client().SetTimeout(500 * time.Millisecond))
      	require.NoError(t, err, "failed to connect to server")
      
      	t.Cleanup(func() {
      		_ = client.Disconnect(context.Background())
      	})
      
      	db := client.Database("exampleDB")
      	collName := "exampleCappedCollection"
      
      	// Drop the collection if it exists
      	_ = db.Collection(collName).Drop(context.Background())
      
      	// Create a capped collection.
      	collOpts := options.CreateCollection().SetCapped(true).SetSizeInBytes(1024 * 1024) // 1 MB capped collection
      
      	err = db.CreateCollection(context.Background(), collName, collOpts)
      	require.NoError(t, err, "failed to create capped collection")
      
      	coll := db.Collection(collName)
      
      	// Insert some documents to ensure the collection exists
      	_, err = coll.InsertMany(context.Background(), []interface{}{
      		bson.D{{Key: "name", Value: "Alice"}},
      		bson.D{{Key: "name", Value: "Bob"}},
      		bson.D{{Key: "name", Value: "Charlie"}},
      	})
      	require.NoError(t, err, "failed to insert documents")
      
      	opts := options.Find().SetMaxAwaitTime(10 * time.Second).SetBatchSize(3).SetCursorType(options.TailableAwait)
      	res, err := coll.Find(context.Background(), bson.D{}, opts)
      	if err != nil {
      		t.Logf("error running Find with MaxAwaitTime: %v", err)
      	}
      
      	fmt.Println("Cursor created with MaxAwaitTime set to 10 seconds")
      
      	//assert.Error(t, err, "expected validation error when using MaxAwaitTime with a non-capped collection")
      
      	// What happens if we use the decoder?
      	for res.Next(context.Background()) {
      		fmt.Println("Found document:", res.Current)
      	}
      
      	if err := res.Err(); err != nil {
      		t.Errorf("cursor error: %v", err)
      	}
      }
      

      Output:

      ❯ go test -run "TestClientLevelTimeoutForCursors" -v -failfast
      === RUN   TestClientLevelTimeoutForCursors
      Cursor created with MaxAwaitTime set to 10 seconds
      Found document: {"_id": {"$oid":"687ed19e6478f989450d6e9b"},"name": "Alice"}
      Found document: {"_id": {"$oid":"687ed19e6478f989450d6e9c"},"name": "Bob"}
      Found document: {"_id": {"$oid":"687ed19e6478f989450d6e9d"},"name": "Charlie"}
      

      Blocks indefinitely, running a getMore every 10 seconds=maxAwaitTimeMS:

      {"getMore": {"$numberLong":"2425290832589901730"},"collection": "exampleCappedCollection","batchSize": {"$numberInt":"3"},"maxTimeMS": {"$numberLong":"10000"},"lsid": {"id": {"$binary":{"base64":"S8lu41B+R726FrVRyjWk0g==","subType":"04"}}},"$clusterTime": {"clusterTime": {"$timestamp":{"t":1753141637,"i":5}},"signature": {"hash": {"$binary":{"base64":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","subType":"00"}},"keyId": {"$numberLong":"0"}}},"$db": "exampleDB"}
      

      Definition of done: what must be done to consider the task complete?

      The methods that use (*mongo.Cursor).next() should respect the effective timeoutMS for the full duration of the call, both for the operational level context deadlines (supported) and client-level timeouts.

            Assignee:
            Preston Vasquez
            Reporter:
            Preston Vasquez
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: