@@ -16,6 +16,7 @@ import (
1616 "time"
1717
1818 "go.mongodb.org/mongo-driver/v2/bson"
19+ "go.mongodb.org/mongo-driver/v2/internal/mongoutil"
1920 "go.mongodb.org/mongo-driver/v2/mongo/options"
2021 "go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
2122 "go.mongodb.org/mongo-driver/v2/x/mongo/driver"
@@ -175,6 +176,32 @@ func (c *Cursor) next(ctx context.Context, nonBlocking bool) bool {
175176 if ctx == nil {
176177 ctx = context .Background ()
177178 }
179+
180+ // To avoid unnecessary socket timeouts, we attempt to short-circuit tailable
181+ // awaitData "getMore" operations by ensuring that the maxAwaitTimeMS is less
182+ // than the operation timeout.
183+ //
184+ // The specifications assume that drivers iteratively apply the timeout
185+ // provided at the constructor level (e.g., (*collection).Find) for tailable
186+ // awaitData cursors:
187+ //
188+ // If set, drivers MUST apply the timeoutMS option to the initial aggregate
189+ // operation. Drivers MUST also apply the original timeoutMS value to each
190+ // next call on the change stream but MUST NOT use it to derive a maxTimeMS
191+ // field for getMore commands.
192+ //
193+ // The Go Driver might decide to support the above behavior with DRIVERS-2722.
194+ // The principal concern is that it would be unexpected for users to apply an
195+ // operation-level timeout via contexts to a constructor and then that timeout
196+ // later be applied while working with a resulting cursor. Instead, it is more
197+ // idiomatic to apply the timeout to the context passed to Next or TryNext.
198+ maxAwaitTime := c .bc .MaxAwaitTime () //
199+ if maxAwaitTime != nil && ! nonBlocking && ! mongoutil .TimeoutWithinContext (ctx , * maxAwaitTime ) {
200+ c .err = fmt .Errorf ("MaxAwaitTime must be less than the operation timeout" )
201+
202+ return false
203+ }
204+
178205 val , err := c .batch .Next ()
179206 switch {
180207 case err == nil :
0 commit comments