@@ -31,27 +31,30 @@ type Cursor struct {
3131 // to Next or TryNext. If continued access is required, a copy must be made.
3232 Current bson.Raw
3333
34- bc batchCursor
35- batch * bsoncore.Iterator
36- batchLength int
37- bsonOpts * options.BSONOptions
38- registry * bson.Registry
39- clientSession * session.Client
40- clientTimeout * time.Duration
34+ bc batchCursor
35+ batch * bsoncore.Iterator
36+ batchLength int
37+ bsonOpts * options.BSONOptions
38+ registry * bson.Registry
39+ clientSession * session.Client
40+ clientTimeout time.Duration
41+ hasClientTimeout bool
4142
4243 err error
4344}
4445
4546type cursorOptions struct {
46- clientTimeout * time.Duration
47+ clientTimeout time.Duration
48+ hasClientTimeout bool
4749}
4850
4951type cursorOption func (* cursorOptions )
5052
5153func withCursorOptionClientTimeout (dur * time.Duration ) cursorOption {
5254 return func (opts * cursorOptions ) {
53- if dur != nil {
54- opts .clientTimeout = dur
55+ if dur != nil && * dur > 0 {
56+ opts .clientTimeout = * dur
57+ opts .hasClientTimeout = true
5558 }
5659 }
5760}
@@ -60,8 +63,9 @@ func newCursor(
6063 bc batchCursor ,
6164 bsonOpts * options.BSONOptions ,
6265 registry * bson.Registry ,
66+ opts ... cursorOption ,
6367) (* Cursor , error ) {
64- return newCursorWithSession (bc , bsonOpts , registry , nil )
68+ return newCursorWithSession (bc , bsonOpts , registry , nil , opts ... )
6569}
6670
6771func newCursorWithSession (
@@ -84,11 +88,12 @@ func newCursorWithSession(
8488 }
8589
8690 c := & Cursor {
87- bc : bc ,
88- bsonOpts : bsonOpts ,
89- registry : registry ,
90- clientSession : clientSession ,
91- clientTimeout : cursorOpts .clientTimeout ,
91+ bc : bc ,
92+ bsonOpts : bsonOpts ,
93+ registry : registry ,
94+ clientSession : clientSession ,
95+ clientTimeout : cursorOpts .clientTimeout ,
96+ hasClientTimeout : cursorOpts .hasClientTimeout ,
9297 }
9398 if bc .ID () == 0 {
9499 c .closeImplicitSession ()
@@ -163,11 +168,17 @@ func NewCursorFromDocuments(documents []any, preloadedErr error, registry *bson.
163168// ID returns the ID of this cursor, or 0 if the cursor has been closed or exhausted.
164169func (c * Cursor ) ID () int64 { return c .bc .ID () }
165170
166- // Next gets the next document for this cursor. It returns true if there were no errors and the cursor has not been
167- // exhausted.
171+ // Next gets the next document for this cursor. It returns true if there were no
172+ // errors and the cursor has not been exhausted.
173+ //
174+ // Next blocks until a document is available or an error occurs. If the context
175+ // expires, the cursor's error will be set to ctx.Err(). In case of an error,
176+ // Next will return false.
168177//
169- // Next blocks until a document is available or an error occurs. If the context expires, the cursor's error will
170- // be set to ctx.Err(). In case of an error, Next will return false.
178+ // If MaxAwaitTime is set, the operation will be bound by the Context's
179+ // deadline. If the context does not have a deadline, the operation will be
180+ // bound by the client-level timeout, if one is set. If MaxAwaitTime is greater
181+ // than the user-provided timeout, Next will return false.
171182//
172183// If Next returns false, subsequent calls will also return false.
173184func (c * Cursor ) Next (ctx context.Context ) bool {
@@ -202,9 +213,9 @@ func (c *Cursor) next(ctx context.Context, nonBlocking bool) bool {
202213
203214 // If the context does not have a deadline we defer to a client-level timeout,
204215 // if one is set.
205- if _ , ok := ctx .Deadline (); ! ok && c .clientTimeout != nil {
216+ if _ , ok := ctx .Deadline (); ! ok && c .hasClientTimeout {
206217 var cancel context.CancelFunc
207- ctx , cancel = context .WithTimeout (context . Background (), * c .clientTimeout )
218+ ctx , cancel = context .WithTimeout (ctx , c .clientTimeout )
208219
209220 defer cancel ()
210221 }
0 commit comments