@@ -12,7 +12,6 @@ import (
1212	"fmt" 
1313	"reflect" 
1414	"strconv" 
15- 	"time" 
1615
1716	"go.mongodb.org/mongo-driver/v2/bson" 
1817	"go.mongodb.org/mongo-driver/v2/internal/csot" 
@@ -103,33 +102,6 @@ type changeStreamConfig struct {
103102	crypt           driver.Crypt 
104103}
105104
106- // validChangeStreamTimeouts will return "false" if maxAwaitTimeMS is set, 
107- // timeoutMS is set to a non-zero value, and maxAwaitTimeMS is greater than or 
108- // equal to timeoutMS. Otherwise, the timeouts are valid. 
109- func  validChangeStreamTimeouts (ctx  context.Context , cs  * ChangeStream ) bool  {
110- 	if  cs .options  ==  nil  ||  cs .client  ==  nil  {
111- 		return  true 
112- 	}
113- 
114- 	maxAwaitTime  :=  cs .options .MaxAwaitTime 
115- 	timeout  :=  cs .client .timeout 
116- 
117- 	if  maxAwaitTime  ==  nil  {
118- 		return  true 
119- 	}
120- 
121- 	if  deadline , ok  :=  ctx .Deadline (); ok  {
122- 		ctxTimeout  :=  time .Until (deadline )
123- 		timeout  =  & ctxTimeout 
124- 	}
125- 
126- 	if  timeout  ==  nil  {
127- 		return  true 
128- 	}
129- 
130- 	return  * timeout  <=  0  ||  * maxAwaitTime  <  * timeout 
131- }
132- 
133105func  newChangeStream (ctx  context.Context , config  changeStreamConfig , pipeline  interface {},
134106	opts  ... options.Lister [options.ChangeStreamOptions ]) (* ChangeStream , error ) {
135107	if  ctx  ==  nil  {
@@ -696,10 +668,33 @@ func (cs *ChangeStream) next(ctx context.Context, nonBlocking bool) bool {
696668}
697669
698670func  (cs  * ChangeStream ) loopNext (ctx  context.Context , nonBlocking  bool ) {
699- 	if  ! validChangeStreamTimeouts (ctx , cs ) {
700- 		cs .err  =  fmt .Errorf ("MaxAwaitTime must be less than the operation timeout" )
671+ 	// To avoid unnecessary socket timeouts, we attempt to short-circuit tailable 
672+ 	// awaitData "getMore" operations by ensuring that the maxAwaitTimeMS is less 
673+ 	// than the operation timeout. 
674+ 	// 
675+ 	// The specifications assume that drivers iteratively apply the timeout 
676+ 	// provided at the constructor level (e.g., (*collection).Find) for tailable 
677+ 	// awaitData cursors: 
678+ 	// 
679+ 	//	If set, drivers MUST apply the timeoutMS option to the initial aggregate 
680+ 	//	operation. Drivers MUST also apply the original timeoutMS value to each 
681+ 	//	next call on the change stream but MUST NOT use it to derive a maxTimeMS 
682+ 	//	field for getMore commands. 
683+ 	// 
684+ 	// The Go Driver might decide to support the above behavior with DRIVERS-2722. 
685+ 	// The principal concern is that it would be unexpected for users to apply an 
686+ 	// operation-level timeout via contexts to a constructor and then that timeout 
687+ 	// later be applied while working with a resulting cursor. Instead, it is more 
688+ 	// idiomatic to apply the timeout to the context passed to Next or TryNext. 
689+ 	if  cs .options  !=  nil  &&  ! nonBlocking  {
690+ 		maxAwaitTime  :=  cs .cursorOptions .MaxAwaitTime 
691+ 
692+ 		// If maxAwaitTime is not set, this check is unnecessary. 
693+ 		if  maxAwaitTime  !=  nil  &&  ! mongoutil .TimeoutWithinContext (ctx , * maxAwaitTime ) {
694+ 			cs .err  =  fmt .Errorf ("MaxAwaitTime must be less than the operation timeout" )
701695
702- 		return 
696+ 			return 
697+ 		}
703698	}
704699
705700	// Apply the client-level timeout if the operation-level timeout is not set. 
0 commit comments