GraphQLGuide / apollo-datasource-mongodb

Apollo data source for MongoDB
MIT License
285 stars 64 forks source link

MongoDB Pool destroyed #56

Closed philios33 closed 3 years ago

philios33 commented 3 years ago

I am worried about over memoization in this NPM package. We are getting "Pool destroyed" errors after a while, which often points to these memoization issues.

The concept you are using here (in README.md) to memoize the MongoDB collection objects within a MongoDataSource class could be considered incorrect usage of the mongodb/MongoClient. You are getting the collection object one time and reusing it as much as possible. But if (or when) mongoDB connection drops, those Collection objects will become stale and link back to a destroyed connection pool. MongoDB clients handle the connection pools and memoization of all resource objects but this requires programmers to get them each time at every request.

E.g. db.collection("users");

If you want to store which collection a MongoDataSource refers to, I suggest storing a string of the collection name. Then access the collection when you need it.

lorensr commented 3 years ago

This is the current README-recommended method of using:

const client = new MongoClient('mongodb://localhost:27017/test')
client.connect()

const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => ({
    users: new Users(client.db().collection('users'))
  })
})

We have a single client instance, and the dataSources function is called at the beginning of each request (see docs), so I don't believe this is the case:

You are getting the collection object one time and reusing it as much as possible.

Perhaps there's another cause of the Pool destroyed error—maybe the client is closed or disconnected? Let me know if you have other ideas, or more of the error message/output/stack. And we can leave this open to see if others have the issue.

philios33 commented 3 years ago

Ah, I didn't realise the dataSources function was called at the beginning of each request. You are absolutely correct, then it is not a problem. Please feel free to close this.

After looking in to my issue further, the Pool destroyed error was caused by the MongoClient "giving up" reconnecting. The default is 30 retries at 1000ms interval, which I think is really bad. If the mongo service goes down for more than 30 seconds, the client gives up and cannot be used anymore.

To fix this, you could remove the reconnect retry limit on the client or just kill the whole node process when the client disconnects. We did the latter so that our container restarts and reconnects properly.