Skip to content

Commit 9a4eecc

Browse files
fix lint and refactor
1 parent 34424ed commit 9a4eecc

File tree

4 files changed

+25
-31
lines changed

4 files changed

+25
-31
lines changed

src/cursor/abstract_cursor.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Readable, Transform } from 'stream';
2-
import { callbackify, promisify } from 'util';
2+
import { promisify } from 'util';
33

44
import { type BSONSerializeOptions, type Document, Long, pluckBSONSerializeOptions } from '../bson';
55
import {
@@ -708,7 +708,10 @@ async function next<T>(
708708
try {
709709
return cursor[kTransform](doc);
710710
} catch (error) {
711-
await cleanupCursorAsync(cursor, { error, needsToEmitClosed: true });
711+
await cleanupCursorAsync(cursor, { error, needsToEmitClosed: true }).catch(() => {
712+
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
713+
// error instead.
714+
});
712715
throw error;
713716
}
714717
}
@@ -725,7 +728,9 @@ async function next<T>(
725728

726729
if (cursorIsDead(cursor)) {
727730
// if the cursor is dead, we clean it up
728-
await cleanupCursorAsync(cursor);
731+
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
732+
// and we should surface the error
733+
await cleanupCursorAsync(cursor, {});
729734
return null;
730735
}
731736

@@ -740,7 +745,10 @@ async function next<T>(
740745
response = await getMore(batchSize);
741746
} catch (error) {
742747
if (error) {
743-
await cleanupCursorAsync(cursor, { error });
748+
await cleanupCursorAsync(cursor, { error }).catch(() => {
749+
// `cleanupCursorAsync` should never throw, but if it does we want to throw the original
750+
// error instead.
751+
});
744752
throw error;
745753
}
746754
}
@@ -762,7 +770,10 @@ async function next<T>(
762770
// we intentionally clean up the cursor to release its session back into the pool before the cursor
763771
// is iterated. This prevents a cursor that is exhausted on the server from holding
764772
// onto a session indefinitely until the AbstractCursor is iterated.
765-
await cleanupCursorAsync(cursor);
773+
//
774+
// cleanupCursorAsync should never throw, but if it does it indicates a bug in the driver
775+
// and we should surface the error
776+
await cleanupCursorAsync(cursor, {});
766777
}
767778

768779
if (cursor[kDocuments].length === 0 && blocking === false) {
@@ -777,20 +788,7 @@ function cursorIsDead(cursor: AbstractCursor): boolean {
777788
return !!cursorId && cursorId.isZero();
778789
}
779790

780-
const cleanupCursorAsyncInternal = promisify(cleanupCursor);
781-
782-
async function cleanupCursorAsync<T>(
783-
cursor: AbstractCursor<T>,
784-
options: { needsToEmitClosed?: boolean; error?: AnyError } = {}
785-
): Promise<void> {
786-
try {
787-
await cleanupCursorAsyncInternal(cursor, options);
788-
} catch {
789-
// `cleanupCursor` never throws but we can't really test that.
790-
// so this is a hack to ensure that any upstream consumers
791-
// can safely guarantee on this wrapper never throwing.
792-
}
793-
}
791+
const cleanupCursorAsync = promisify(cleanupCursor);
794792

795793
function cleanupCursor(
796794
cursor: AbstractCursor,
@@ -802,6 +800,10 @@ function cleanupCursor(
802800
const server = cursor[kServer];
803801
const session = cursor[kSession];
804802
const error = options?.error;
803+
804+
// Cursors only emit closed events once the client-side cursor has been exhausted fully or there
805+
// was an error. Notably, when the server returns a cursor id of 0 and a non-empty batch, we
806+
// cleanup the cursor but don't emit a `close` event.
805807
const needsToEmitClosed = options?.needsToEmitClosed ?? cursor[kDocuments].length === 0;
806808

807809
if (error) {

test/integration/crud/misc_cursors.test.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,6 @@ describe('Cursor', function () {
17081708
expect(cursor).property('closed', false);
17091709

17101710
const willClose = once(cursor, 'close');
1711-
const willEnd = once(stream, 'close');
17121711

17131712
const dataEvents = on(stream, 'data');
17141713

@@ -1722,16 +1721,12 @@ describe('Cursor', function () {
17221721
// After 5 successful data events, destroy stream
17231722
stream.destroy();
17241723

1725-
// We should get a a close event on the stream and a close event on the cursor
1726-
// We should **not** get an 'error' event,
1724+
// We should get a close event on the stream and a close event on the cursor
1725+
// We should **not** get an 'error' or an 'end' event,
17271726
// the following will throw if either stream or cursor emitted an 'error' event
1728-
await Promise.race([
1729-
willEnd,
1730-
sleep(100, { ref: false }).then(() => Promise.reject(new Error('end event never emitted')))
1731-
]);
17321727
await Promise.race([
17331728
willClose,
1734-
sleep(100, { ref: false }).then(() => Promise.reject(new Error('close event never emitted')))
1729+
sleep(100).then(() => Promise.reject(new Error('close event never emitted')))
17351730
]);
17361731
});
17371732

@@ -3606,7 +3601,6 @@ describe('Cursor', function () {
36063601

36073602
await collection.insertMany(docs);
36083603

3609-
// TODO - talk to Neal about this test
36103604
const cursor = await collection.find({}, { batchSize: 3 });
36113605
for (let i = 0; i < 3; ++i) {
36123606
await cursor.next();

test/integration/node-specific/abstract_cursor.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ describe('class AbstractCursor', function () {
117117
expect(doc.name).to.equal('JOHN DOE');
118118
});
119119

120-
// skipped because these tests fail after throwing uncaught exceptions
121120
it(`when the transform throws, Cursor.stream() propagates the error to the user`, async () => {
122121
const cursor = collection
123122
.find()

test/integration/node-specific/cursor_stream.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict';
22
const { expect } = require('chai');
33
const { Binary } = require('../../mongodb');
4-
const { setTimeout, setImmediate } = require('timers');
4+
const { setTimeout } = require('timers');
55

66
describe('Cursor Streams', function () {
77
let client;
@@ -296,7 +296,6 @@ describe('Cursor Streams', function () {
296296
const stream = cursor.stream();
297297
stream.on('error', err => (error = err));
298298
cursor.on('close', function () {
299-
// NOTE: use `setImmediate` here because the stream implementation uses `nextTick` to emit the error
300299
setTimeout(() => {
301300
expect(error).to.exist;
302301
client.close(done);

0 commit comments

Comments
 (0)