Uploaded image for project: 'Node.js Driver'
  1. Node.js Driver
  2. NODE-6346

use of performance is causing errors on node v20

    • Type: Icon: Bug Bug
    • Resolution: Works as Designed
    • Priority: Icon: Unknown Unknown
    • None
    • Affects Version/s: None
    • Component/s: Performance
    • 1
    • Not Needed
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      When running the driver and connecting to a database in node v20, the following error occurs:

      TypeError: Cannot read properties of undefined (reading 'now')
          at new Timeout (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/timeout.ts:58:41)
          at Function.expires (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/timeout.ts:82:12)
          at Topology.selectServer (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/sdam/topology.ts:585:29)
          at Topology._connect (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/sdam/topology.ts:463:33)
          at Topology.connect (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/sdam/topology.ts:408:34)
          at topologyConnect (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/mongo_client.ts:554:30)
          at MongoClient._connect (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/mongo_client.ts:566:13)
          at MongoClient.connect (/path/to/project/node_modules/.pnpm/mongodb@6.7.0_socks@2.8.3/node_modules/mongodb/src/mongo_client.ts:477:34)
          at NativeConnection.createClient (/path/to/project/node_modules/.pnpm/mongoose@8.5.3_socks@2.8.3/node_modules/mongoose/lib/drivers/node-mongodb-native/connection.js:314:16)
          at NativeConnection.openUri (/path/to/project/node_modules/.pnpm/mongoose@8.5.3_socks@2.8.3/node_modules/mongoose/lib/connection.js:823:34)
          at Mongoose.Object.<anonymous>.Mongoose.createConnection (/path/to/project/node_modules/.pnpm/mongoose@8.5.3_socks@2.8.3/node_modules/mongoose/lib/mongoose.js:389:10)
          at Function.createMongooseConnection (/path/to/project/node_modules/.pnpm/@nestjs+mongoose@10.0.10_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_b7e7azbc32kdk3npgmil5pjkwi/node_modules/@nestjs/mongoose/dist/mongoose-core.module.js:114:37)
          at /path/to/project/node_modules/.pnpm/@nestjs+mongoose@10.0.10_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_b7e7azbc32kdk3npgmil5pjkwi/node_modules/@nestjs/mongoose/dist/mongoose-core.module.js:65:123
          at Observable._subscribe (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/observable/defer.ts:55:15)
          at Observable.Object.<anonymous>.Observable._trySubscribe (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:244:19)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:234:18
          at Object.errorContext (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/util/errorContext.ts:29:5)
          at Observable.Object.<anonymous>.Observable.subscribe (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:220:5)
          at subscribeForRetryWhen (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/operators/retryWhen.ts:74:25)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/operators/retryWhen.ts:111:5
          at OperatorSubscriber.<anonymous> (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/util/lift.ts:24:18)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:226:22
          at Object.errorContext (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/util/errorContext.ts:29:5)
          at Observable.Object.<anonymous>.Observable.subscribe (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:220:5)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/operators/catchError.ts:115:23
          at SafeSubscriber.<anonymous> (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/util/lift.ts:24:18)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:226:22
          at Object.errorContext (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/util/errorContext.ts:29:5)
          at Observable.Object.<anonymous>.Observable.subscribe (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/Observable.ts:220:5)
          at /path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/lastValueFrom.ts:59:12
          at new Promise (<anonymous>)
          at lastValueFrom (/path/to/project/node_modules/.pnpm/rxjs@7.8.1/node_modules/rxjs/src/internal/lastValueFrom.ts:56:10)
          at InstanceWrapper.useFactory [as metatype] (/path/to/project/node_modules/.pnpm/@nestjs+mongoose@10.0.10_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_b7e7azbc32kdk3npgmil5pjkwi/node_modules/@nestjs/mongoose/dist/mongoose-core.module.js:65:55)
          at TestingInjector.instantiateClass (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/injector.js:368:55)
          at callback (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/injector.js:65:45)
          at processTicksAndRejections (node:internal/process/task_queues:95:5)
          at TestingInjector.resolveConstructorParams (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/injector.js:144:24)
          at TestingInjector.loadInstance (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/injector.js:70:13)
          at TestingInjector.loadProvider (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/injector.js:97:9)
          at /path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/instance-loader.js:56:13
          at async Promise.all (index 4)
          at TestingInstanceLoader.createInstancesOfProviders (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/instance-loader.js:55:9)
          at /path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/instance-loader.js:40:13
          at async Promise.all (index 9)
      form/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/instance-loader.js:39:9)
          at TestingInstanceLoader.createInstancesOfDependencies (/path/to/project/node_modules/.pnpm/@nestjs+core@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_refl_cm7eoljwmhxzk4jjou7u2pgemq/node_modules/@nestjs/core/injector/instance-loader.js:22:13)
          at TestingInstanceLoader.createInstancesOfDependencies (/path/to/project/node_modules/.pnpm/@nestjs+testing@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_r_4fkxwolokzjrsak3izk6eol6ga/node_modules/@nestjs/testing/testing-instance-loader.js:9:9)
          at TestingModuleBuilder.createInstancesOfDependencies (/path/to/project/node_modules/.pnpm/@nestjs+testing@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_r_4fkxwolokzjrsak3izk6eol6ga/node_modules/@nestjs/testing/testing-module.builder.js:118:9)
          at TestingModuleBuilder.compile (/path/to/project/node_modules/.pnpm/@nestjs+testing@10.3.8_@nestjs+common@10.3.8_class-transformer@0.5.1_class-validator@0.14.0_r_4fkxwolokzjrsak3izk6eol6ga/node_modules/@nestjs/testing/testing-module.builder.js:74:9)

      The fix appears to be to import performance from the perf_hooks package for better compatibility in different versions of Node.js as in this patch:

      diff --git a/lib/timeout.js b/lib/timeout.jsindex 758aeef9f54a5f1c31b4aa75945374b34e904ee3..40970fa4af4836b351434249012c2c7668843446 100644--- a/lib/timeout.js+++ b/lib/timeout.js@@ -1,6 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Timeout = exports.TimeoutError = void 0;+const performance_1 = require("perf_hooks"); const timers_1 = require("timers"); const error_1 = require("./error"); const utils_1 = require("./utils");@@ -40,10 +41,10 @@ class Timeout extends Promise {         this.ended = null;         this.timedOut = false;         this.duration = duration;-        this.start = Math.trunc(performance.now());+        this.start = Math.trunc(performance_1.performance.now());         if (this.duration > 0) {             this.id = (0, timers_1.setTimeout)(() => {-                this.ended = Math.trunc(performance.now());+                this.ended = Math.trunc(performance_1.performance.now());                 this.timedOut = true;                 reject(new TimeoutError(`Expired after ${duration}ms`));             }, this.duration);diff --git a/src/timeout.ts b/src/timeout.tsindex 7d0af2383d3ec2860da9550db7183b7b1f6dd08f..433ee081bf7fdc895ec69bf93a042320dc4e9798 100644--- a/src/timeout.ts+++ b/src/timeout.ts@@ -1,3 +1,4 @@+import { performance } from 'perf_hooks'; import { clearTimeout, setTimeout } from 'timers';  import { MongoInvalidArgumentError } from './error';
       

      Use Case

      As a user using v20 of Node.js
      I want my app not to crash when I use the mongodb node driver
      So that my app can function properly

      User Experience

      • What is the desired/expected outcome for the user once this ticket is implemented?
        • A bug fix is released
      • If bug: What is the number of impacted customers? How severe is the impact? Is anyone blocked or broken?
        • I would imagine anyone using node v20 or lower

      Dependencies

      • Mongoose v8.5.3 (latest version as of this writing) has mongodb pinned at v6.7.0. We'll need to work with them bring in the latest version of mongodb

      Risks/Unknowns

      • What could go wrong while implementing this change? (e.g., performance, inadvertent behavioral changes in adjacent functionality, existing tech debt, etc)
        • It feels like a fairly low risk change, just need to test this with all supported versions of Node.js
      • Is there an opportunity for better cross-driver alignment or testing in this area?
        • :shrug:
      • Is there an opportunity to improve existing documentation on this subject?
        • No new documentation should be required as far as I know...

      Acceptance Criteria

      Implementation Requirements

      • functional reqs, potential snafus to avoid, performance targets, etc

      Testing Requirements

      • unit test, spec test sync, etc

      Documentation Requirements

      • DOCSP ticket, API docs, etc

      Follow Up Requirements

      • additional tickets to file, required releases, etc
      • if node behavior differs/will differ from other drivers, confirm with dbx devs what standard to aim for and what plan, if any, exists to reconcile the diverging behavior moving forward

            Assignee:
            bailey.pearson@mongodb.com Bailey Pearson
            Reporter:
            doug@swellcx.com Doug Ludlow
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: