-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Feature: Where should we put this documentation on reconnection and serverSelectionTimeoutMs? #12967
Comments
See above @vkarpov15 - this is also going to be pushed up to the codebase at https://github.com/forwardemail/forwardemail.net later today most likely. |
Another thing we do is alert users if we have an issue with database connections (website outage): app.use((ctx, next) => {
// if either mongoose or redis are not connected
// then render website outage message to users
const isMongooseDown = mongoose.connections.some(
(conn) => conn.readyState !== mongoose.ConnectionStates.connected
);
const isRedisDown = !ctx.client || ctx.client.status !== 'ready';
if (isMongooseDown || isRedisDown)
ctx.logger.fatal(new Error('Website outage'), {
mongoose: mongoose.connections.map((conn) => ({
id: conn.id,
readyState: conn.readyState,
name: conn.name,
host: conn.host,
port: conn.port
})),
redis: {
status: ctx.client.status,
description: ctx.client._getDescription()
}
});
if (
ctx.method === 'GET' &&
ctx.accepts('html') &&
(isMongooseDown || isRedisDown)
)
ctx.flash('warning', ctx.translate('WEBSITE_OUTAGE'));
return next();
}); |
Okay! 🎉 Team here from Forward Email! https://forwardemail.net - the 100% open-source email hosting service We actually finally figured out how to make this work and implemented it... 🤦 It's super hacky right now because of the following discoveries:
This required us to create a custom wrapper for Here's the working code: // eslint-disable-next-line import/no-unassigned-import
require('#config/env');
// eslint-disable-next-line import/no-unassigned-import
require('#config/mongoose');
const process = require('process');
const Graceful = require('@ladjs/graceful');
const Redis = require('@ladjs/redis');
const Web = require('@ladjs/web');
const ip = require('ip');
const mongoose = require('mongoose');
const pRetry = require('p-retry');
const sharedConfig = require('@ladjs/shared-config');
const Users = require('#models/users');
const config = require('#config');
const logger = require('#helpers/logger');
const webConfig = require('#config/web');
const webSharedConfig = sharedConfig('WEB');
const redis = new Redis(
webSharedConfig.redis,
logger,
webSharedConfig.redisMonitor
);
const web = new Web(webConfig(redis), Users);
const graceful = new Graceful({
mongooses: [mongoose],
servers: [web.server],
redisClients: [redis],
logger
});
graceful.listen();
(async () => {
try {
await web.listen(web.config.port);
if (process.send) process.send('ready');
const { port } = web.server.address();
logger.info(
`Lad web server listening on ${port} (LAN: ${ip.address()}:${port})`,
{ hide_meta: true }
);
if (config.env === 'development')
logger.info(
`Please visit ${config.urls.web} in your browser for testing`,
{ hide_meta: true }
);
//
// this will attempt to reconnect with exponential backoff up to 10x
// however if there is not a MongooseServerSelectionError, it will throw
// (this is useful to keep http server running and retry db connection)
// (apps such as pm2 are recommended to cause app to reboot if this eventually throws)
// <https://github.com/Automattic/mongoose/issues/12967>
// <https://github.com/Automattic/mongoose/issues/12965>
// <https://github.com/Automattic/mongoose/issues/12966>
// <https://github.com/Automattic/mongoose/issues/12968>
// <https://github.com/Automattic/mongoose/issues/12970>
// <https://github.com/Automattic/mongoose/issues/12971>
//
await pRetry(
() =>
Promise.all(
mongoose.connections
.filter(
(c) => c.readyState === mongoose.ConnectionStates.disconnected
)
//
// NOTE: our version of `asPromise` contains magic per <https://github.com/Automattic/mongoose/issues/12970>
// see @ladjs/mongoose package source code for more insight into how this works
//
.map((c) => c.asPromise())
),
{
// <https://github.com/sindresorhus/p-retry/issues/58>
// <https://github.com/tim-kos/node-retry/issues/84>
// forever: true,
// retries: Infinity,
onFailedAttempt(err) {
logger.fatal(err);
if (!(err instanceof mongoose.Error.MongooseServerSelectionError))
throw err;
}
}
);
} catch (err) {
logger.fatal(err);
process.exit(1);
}
})(); |
You could always just increase |
if you have documentation about something like options, like usage of mongoose does not currently list integration examples (aside from typescript) on the documentation website itself, but feel free to add your guide in |
docs(connections): expand docs on serverSelectionTimeoutMS
Prerequisites
🚀 Feature Proposal
We've done some complex connection management, and wanted to share some patterns we used.
For example, if you have an Express or Koa app, such as
app.js
, you can set it up such as:For single connection:
For multiple connections:
Did you want to put this in documentation and as an example somewhere for users? If so let us know where - or feel free to add it wherever you deem best fit!
Motivation
Lack of real documentation and examples surrounding connection on application boot with
serverSelectionTimeoutMS
and how to properly handle it in real-world Express, Koa, Fastify, etc.The text was updated successfully, but these errors were encountered: