mongoose.connect() doesn't return a promise in Angular universal, when using 'srv' in uri string

Created on 25 May 2019  路  23Comments  路  Source: Automattic/mongoose

in server.ts (express server):

import mongoose from "mongoose"
app.get("/articles/api/*", (req, res) => {
  console.log("aaa")
   mongoose.connect(uri,{}) //uri is the connection string
       .then(db=>{
             console.log("connected")
            db.model(...) 
  })
      .catch(error=>console.log(error))

  //res.send(...)
});

neither .then() nor .catch() is called, but 'aaa' is called, means that the express path works fine
note1: running this code outside of angular works fine
note2: console.log(mongoose.connect(uri)) in Angular returns zone (not promise):
ZoneAwarePromise { __zone_symbol__state: null, __zone_symbol__value: [] }

when replacing mongoose.connect(..) with new Promise(r=>r()) it works fine

update:
when removing +srv from the connection string it works with error i.e: catche() runs, but with 'srv' neither .then() or .catch() runs

underlying library issue

Most helpful comment

This should be fixed in Mongoose 5.7.10 :+1:

All 23 comments

Worth looking into. Do you have a sample project using angular universal?

https://github.com/xxyyzz2050/eldeebCMS
@vkarpov15

check this file: ./server.ts

app.get("/articles/api/*", (req, res) => {
  const GetArticlesAPI = require("./src/app/articles/get-articles.api")
    .GetArticlesAPI;
  new GetArticlesAPI().get(req.url).then(data => res.json(data));
});

GetArticlesAPI().get(req.url) returns a promise

Will investigate this more. But just FYI, you shouldn't call mongoose.connect() in a route handler, see this FAQ

also error handler (and all events) never be called

I suspect this is something weird with the mongodb server you're connecting to and/or your options parsing. I replaced your connect() function with one that connects to localhost:

export function connect(options: types.ConnectionOptions | string) {
  console.log("*** mongoose.connect() ***");
  let uri: string,
    defaultOptions = {
      useCreateIndex: true,
      useNewUrlParser: true, //https://mongoosejs.com/docs/deprecations.html; now it gives "MongoError: authentication fail"
      useFindAndModify: false,
      bufferCommands: false, //https://mongoosejs.com/docs/connections.html
      autoIndex: false,
      retryWrites: true
    };

  uri = 'mongodb://localhost:27017/test'

  console.log("uri: ", uri);
  //todo: return Promise<this mongoose, not Mongoose>

  return mongoose.connect(
    uri,
    defaultOptions
  ).then(() => console.log('Connected!'));
}

And now it works as expected:

[nodemon] 1.19.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node dist/server --inspaect`
Node Express server listening on http://localhost:4200
*** mongoose.connect() ***
uri:  mongodb://localhost:27017/test
Connected!
===model===
XX: { title: 'Title', content: 'Content' }

so, why it didn't reject the promise?

important: the error appears when you use (srv) in your uri string, i.e: mongodb+srv://.....
I added an update to the issue, please check it

the same uri string worked fine in an express server
I created a repo for you to try it out

https://github.com/xxyyzz2050/tmp_mongoose_issue

just run express.js and open localhost:4200

is there any news? @vkarpov15
I checked the new version 5.6.1, but the same issue still not resolved

I'm getting an error when I run this project now:

$ npm start

> [email protected] start /home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS
> npm run build  && npm run serve:server


> [email protected] build /home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS
> npm run build:browser && npm run build:server


> [email protected] build:browser /home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS
> ng build --prod

Unknown browser query `> 0.5 %`. Maybe you are using old Browserslist or made typo in query.
BrowserslistError: Unknown browser query `> 0.5 %`. Maybe you are using old Browserslist or made typo in query.
    at unknownQuery (/home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS/node_modules/browserslist/index.js:176:10)
    at /home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS/node_modules/browserslist/index.js:256:11
    at Array.reduce (<anonymous>)
    at resolve (/home/val/Workspace/MongoDB/troubleshoot-mongoose/eldeebCMS/node_modules/browserslist/index.js:197:18)

Realistically, I won't be able to debug this. There's simply too much code in this project for me to be able to figure out what the issue is. I can confirm Mongoose works fine with Zone.js:

const x = require('zone.js');

console.log(global.Promise) // ZoneAwarePromise

  const mongoose = require("mongoose");
  mongoose
    .connect(
      "mongodb+srv://xxyyzz2050:Xx159753%2540%[email protected]/test?retryWrites=true&w=majority"
    )
    .then(db => console.log(db))
    .catch(e => console.error(e));

So the issue isn't promise based, it's something in the angular config. If you can come up with a more minimal repro script, I can re-open this issue.

use this repo:
https://github.com/xxyyzz2050/angular-mongoose

read README.md & check the commits (if needed) to view how to reproduce the issue step-by-step

  • also, the error Unknown browser query > 0.5 % in the main repo has been fixed.
    @vkarpov15

I'll give this another shot :+1:

many thanks for your great efforts @vkarpov15

I think I may have found the issue :point_up: We'll see what happens with that.

But in the meantime, the only workaround I can find is not importing Zone.js. The issue comes down to Zone.js monkey-patching event emitters with cancellation logic.

so, what is your recommended action to do in this example repo? @vkarpov15

Remove Zone.js until these changes land in a new release of the mongodb node driver and Mongoose picks up those changes. Unfortunately the issue is with a non-exported variable deep in the MongoDB driver, so there's no way to work around this issue until the mongodb driver releases a fix.

I also encountered the same problem...

@vkarpov15

How hard would it be to determine whether an issue that I am facing is caused by the same underlying problem?

I have created a truly simple (single-file) demo repo (https://github.com/juona/mongoose-zonejs).

The problem is that when I use Mongoose in combination with Zone.js (same as @xxyyzz2050 ), and try to connect to a cluster (replica set) on Atlas, it does not work - the program simply exits. My investigation has not yielded much - it appears that the handshake requests are sent to the socket yet I do not receive any responses, after which the application decides that it has run to completion and exits without printing anything. It feels like "the execution context is lost" at some point due to an incompatibility with Zone.js but I haven't been able to find where.

This does not happen if I connect to the same cluster (same URL) using the official MongoDB driver _or_ if I do not use Zone.js.

This does not happen when connecting to a simple MongoDB server hosted locally. I also tried hosting a replica set on my machine and connecting to it using a non-SRV URL, and it works just fine. However, using a non-SRV URL to connect to Atlas does not help.

@juona we're still waiting on the mongodb driver to release our patch. Unfortunately there's no workaround currently besides disabling zone.js or not using Atlas

Using the non-SRV URL from Mongo Atlas to connect doesn't call any callback as well.

mongodb://<username>:<password>@test-dev-shard-00-00-kboew.mongodb.net:27017,test-dev-shard-00-01-kboew.mongodb.net:27017,test-dev-shard-00-02-kboew.mongodb.net:27017/test?ssl=true&replicaSet=test-dev-shard-0&authSource=admin&retryWrites=true&w=majority

Has anyone found a workaround?

Here's what I did to work around this problem, perhaps it will be useful to someone.

Since in my Node back-end Zone.js was only required for Angular Universal and nothing else, I only needed to find a way to run the rendering process in an isolated JavaScript environment. This could be easily achieved via a child process. Here's the basic idea in steps:

  1. Collect all the code required for Angular Universal, including Zone.js, all the Angular stuff, and whatever else, and extract that to a single file.
  2. Allow that process to communicate with its _parent_ via process.on and process.send in such a way that when the parent sends a "render request", this little process would perform the render and send a message back, which would contain the rendered HTML.
  3. The main Node application then launches the renderer using fork from child_process.
  4. Finally you have to set up the application to send rendering requests when necessary and be able to properly respond to the messages it gets back from the renderer. E.g. I am using the Express framework and basically the only thing I had to do was write an HTML engine using app.engine.

I can elaborate and share pieces of code if needed, but not the whole thing as its a commercial project.

Also, disclaimer - not battle-tested, although right now I can't see why this would not work.

This should be fixed in Mongoose 5.7.10 :+1:

the same issue exists in mongoose 5.7.13

@eng-dibo please open up a new issue with detailed code samples and follow the issue template. As far as I can tell, this issue is fixed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArThoX picture ArThoX  路  3Comments

p3x-robot picture p3x-robot  路  3Comments

jeneser picture jeneser  路  3Comments

simonxca picture simonxca  路  3Comments

weisjohn picture weisjohn  路  3Comments