-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(connection): avoid returning readyState = connected
if connection state is stale
#14812
Conversation
…on state is stale Fix #14727
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good to me, though i agree this should need some testing
Going to move this one back because I've been having trouble reproducing this issue in AWS lambda |
It took some time, but I was able to repro this in Lambda. The following function is adapted from Mongoose's Lambda docs: const mongoose = require('mongoose');
let conn = null;
const uri = 'mongodb+srv://chris2022:PennywinklePlaydays@zevo-dev.6lxkgiz.mongodb.net/chris2022?retryWrites=true&w=majority';
exports.handler = async function(event, context) {
// Make sure to add this so you can re-use `conn` between function calls.
// See https://www.mongodb.com/blog/post/serverless-development-with-nodejs-aws-lambda-mongodb-atlas
context.callbackWaitsForEmptyEventLoop = false;
// Because `conn` is in the global scope, Lambda may retain it between
// function calls thanks to `callbackWaitsForEmptyEventLoop`.
// This means your Lambda function doesn't have to go through the
// potentially expensive process of connecting to MongoDB every time.
if (conn == null) {
conn = mongoose.createConnection(uri, {
// and tell the MongoDB driver to not wait more than 5 seconds
// before erroring out if it isn't connected
serverSelectionTimeoutMS: 5000
});
// `await`ing connection after assigning to the `conn` variable
// to avoid multiple function calls creating new connections
await conn.asPromise();
conn.model('Test', new mongoose.Schema({ name: String }));
}
console.log('Start', conn.readyState, new Date(conn._lastHeartbeatAt), Date.now() - conn._lastHeartbeatAt);
const M = conn.model('Test');
const doc = await M.findOne();
console.log('After find', conn.readyState, new Date(conn._lastHeartbeatAt), Date.now() - conn._lastHeartbeatAt);
console.log(doc);
return doc;
}; Output:
So |
This logic seems overly aggressive. Network latencies caused by high load on the MongoDB server could prevent heartbeats from being received within the heartbeatFrequencyMS * 2 time frame. Relying on such logic may lead Mongoose to falsely report a disconnected state. If this implementation is necessary for cold-start environments, it should be configurable and invoked only when required. Additionally, a more reliable method for detecting staleness should be employed. FYI |
It seems there are already couple of issues opened related with this. @vkarpov15 |
Fix #14727
cc @alexbevi
Summary
The problem here is that
readyState
can returnconnected
immediately after an AWS Lambda container thaws after some time.readyState
only looks at the last heartbeat, but not how long ago the last heartbeat occurred - with this PR, if the last heartbeat is stale (more than 2 heartbeat intervals) then we assume we're disconnected.This PR still needs significant testing, but I wanted to put it out for review to solicit early feedback.
Examples