Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

A node.js stream polyfill issue: the error thrown within the process.nextTick callback cannot be caught, leading to unexpected exit when connection closed #24376

Closed
TyanSia opened this issue Jul 1, 2024 · 1 comment · Fixed by #24656
Labels
bug Something isn't working correctly node compat

Comments

@TyanSia
Copy link

TyanSia commented Jul 1, 2024

Description: I'm encountering a problem while running a script which makes a connection to MongoDB v6.8.0. Initially, everything works fine, but after a network connection break, any further query to the database will cause the proces to exit abruptly, alongside an uncatchable uncaught error (connect ECONNREFUSED).

Deno: Version 1.44.4
MongoDB: MongoDB driver for Node.js, mongodb@6.8.0

Relevant Error Output:

error: Uncaught Error: connect ECONNREFUSED 127.0.0.1:27017 - Local (undefined:undefined)
    at __node_internal_captureLargerStackTrace (ext:deno_node/internal/errors.ts:93:9)
    at __node_internal_exceptionWithHostPort (ext:deno_node/internal/errors.ts:217:10)
    at TCPConnectWrap._afterConnect [as oncomplete] (node:net:171:16)
    at TCP.afterConnect (ext:deno_node/internal_binding/connection_wrap.ts:43:11)
    at ext:deno_node/internal_binding/tcp_wrap.ts:302:14
    at eventLoopTick (ext:core/01_core.js:168:7)

Here is the program code:

// main.js
import { MongoClient }  from 'npm:mongodb';

async function main(){
  const uri = "mongodb://127.0.0.1:27017";

  const client = new MongoClient(uri);

  try {
      // Connect to the MongoDB cluster
      await client.connect();

      setInterval(async () => {
        await listDatabases(client);
      }, 2000);

  } catch (e) {
      console.error('main error', e);
      // await client.close();
  }
}

main();

async function listDatabases(client){
  try {
    const databasesList = await client.db().admin().listDatabases();

    console.log("Databases:", databasesList.databases.map(db => `${db.name}`).join(', '));
  } catch (e) {
    console.error('listDatabases error', e);
  }
};

In this code, I'd like to keep the process running even a network disconnection happens. However, the outcome is not expected.

Digging-in: It seems like the error stems from Deno's _stream.mjs, which is a Node.js polyfill. Specifically, an error thrown within a process.nextTick callback in the stream's destroy logic isn't being caught, and cannot be caught in the main process.

// function _destroy(self2, err, cb) {
// ...
process.nextTick(emitErrorCloseNT, self2, err2); // error in the nextTick is uncaught
// ...

// ...
function emitErrorCloseNT(self2, err) {
      emitErrorNT(self2, err);
      emitCloseNT(self2);
}
// ...

// ...
function emitErrorNT(self2, err) {
      const r = self2._readableState;
      const w = self2._writableState;
      if (w && w.errorEmitted || r && r.errorEmitted) {
        return;
      }
      if (w) {
        w.errorEmitted = true;
      }
      if (r) {
        r.errorEmitted = true;
      }
      self2.emit("error", err); // error in the nextTick is uncaught
}
// ...

// EventEmitter.prototype.emit = function emit(type) {
// ...
if (er instanceof Error) {
      throw er; // throw an error
}
// ...

Comparison with Node.js: When the same script is executed using Node.js v22.1.0 (with the MongoDB import adjusted to import { MongoClient } from 'mongodb';), the error MongoNetworkError: connect EHOSTUNREACH is caught, and the main process does not exit unexpectedly.

This is where as far as I can take it for now.

Possibly related issues
#21951
#16633
#19078
#23665
Automattic/mongoose#14237

Request for Help: I'm looking for assistance to understand why this discrepancy exists between Deno and Node.js, and how to correctly handle MongoDB disconnection errors in Deno to prevent the program from crashing. Any insights or solutions for this issue would be greatly appreciated.

@marvinhagemeister marvinhagemeister added bug Something isn't working correctly node compat labels Jul 1, 2024
@marvinhagemeister
Copy link
Contributor

Spent some time looking into this but haven't found the root cause yet. I have the suspicion that something is different in the way we connect sockets under the hood and how errors are propagated there.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working correctly node compat
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants