I have an EC2 (RHEL) instance running a NodeJS server. I have setup the start of this server as a systemd service (included below) and run this service via a shell script executed during the ApplicationStart part of CodeDeploy LifeCycleEvent.
In the server itself, I am using mongoose
to connect to MongoDB running on another EC2 instance.
My problem is that my server does not connect to MongoDB and instead returns the following error:
{
message: 'Could not connect to MongoDB!!! getaddrinfo ENOTFOUND undefined',
reason: TopologyDescription {
type: 'Single',
setName: null,
maxSetVersion: null,
maxElectionId: null,
servers: Map {
'undefined:27017' => ServerDescription {
address: 'undefined:27017',
error: Error: getaddrinfo ENOTFOUND undefined
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:66:26) {
name: 'MongoNetworkError'
},
roundTripTime: -1,
lastUpdateTime: 23933862843,
lastWriteDate: null,
opTime: null,
type: 'Unknown',
topologyVersion: undefined,
minWireVersion: 0,
maxWireVersion: 0,
hosts: [],
passives: [],
arbiters: [],
tags: []
}
},
stale: false,
compatible: true,
compatibilityError: null,
logicalSessionTimeoutMinutes: null,
heartbeatFrequencyMS: 10000,
localThresholdMS: 15,
commonWireVersion: null
},
level: 'error',
stack: 'MongooseServerSelectionError: getaddrinfo ENOTFOUND undefined\n' +
' at NativeConnection.Connection.openUri (/home/centos/my-server/node_modules/mongoose/lib/connection.js:847:32)\n' +
' at /home/centos/my-server/node_modules/mongoose/lib/index.js:351:10\n' +
' at /home/centos/my-server/node_modules/mongoose/lib/helpers/promiseOrCallback.js:32:5\n' +
' at new Promise (<anonymous>)\n' +
' at promiseOrCallback (/home/centos/my-server/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:10)\n' +
' at Mongoose._promiseOrCallback (/home/centos/my-server/node_modules/mongoose/lib/index.js:1149:10)\n' +
' at Mongoose.connect (/home/centos/my-server/node_modules/mongoose/lib/index.js:350:20)\n' +
' at module.exports (/home/centos/my-server/startup/db.js:20:6)\n' +
' at startServer (/home/centos/my-server/index.js:22:9)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:97:5)',
label: 'qa-server',
timestamp: '1/21/2022, 11:41:15 AM'
}
I tried the following solutions and these did not work:
1.
https://aws.amazon.com/premiumsupport/knowledge-center/dns-resolution-failures-ec2-linux/
2.
Adding the following lines to my .service
file:
After=network-online.target
Wants=network-online.target
If anyone could provide some insight as to how I can solve this, it'd be greatly appreciated.
appspec.yaml
version: 0.0
os: linux
files:
- source: /
destination: /home/centos/my-server
hooks:
BeforeInstall:
- location: scripts/cleanup.sh
timeout: 300
runas: root
AfterInstall:
- location: scripts/install_dependencies.sh
timeout: 300
runas: root
- location: scripts/update_service.sh
timeout: 300
runas: root
ApplicationStart:
- location: scripts/start_server.sh
timeout: 300
runas: root
ApplicationStop:
- location: scripts/stop_server.sh
timeout: 300
runas: root
start_server.sh
#!/bin/bash
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 9080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 9443
sudo systemctl daemon-reload
sudo systemctl restart myserver.service
myserver.service
[Unit]
Description=Node.js My server
[Service]
ExecStart=/usr/bin/node /home/centos/my-server/index.js
WorkingDirectory=/home/centos/my-server/
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=my-server-log
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
index.js
const winston = require('winston');
const express = require('express');
const logging = require('./startup/logging');
const config = require('./startup/config');
const routes = require('./startup/routes');
const db = require('./startup/db');
const validation = require('./startup/validation');
const redirect = require('./startup/redirect');
const app = express();
const successMessage = async () => {
const message = 'my-server is up and running and ready for requests..';
winston.info(message);
console.log(message);
};
const startServer = async () => {
await logging();
await config();
await routes(app);
await db();
await validation();
await redirect(app);
await successMessage();
};
startServer();
db.js
const mongoose = require('mongoose');
const winston = require('winston');
const nconf = require('nconf');
const fs = require('fs');
module.exports = async function () {
// Get the mongodb credentials from config memory
const ipAddress = fs.existsSync('/.dockerenv')
? nconf.get('mongodb:dockerIPAddress')
: nconf.get('mongodb:ipAddress');
const port = nconf.get('mongodb:port');
const username = encodeURIComponent(nconf.get('mongodb:username'));
const password = encodeURIComponent(nconf.get('mongodb:password'));
const database = nconf.get('mongodb:database');
const mongoUrl = `mongodb://${username}:${password}@${ipAddress}:${port}/${database}?authSource=admin`;
mongoose
.connect(mongoUrl, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
})
.then(() => winston.info('Connected to mongodb successfully..'))
.catch((err) => winston.error('Could not connect to MongoDB!!!', err));
};
Hi Wayne,
Thank you for responding. That's it. That was the problem. Though I do have your solution implemented in my
config.js
file which is executed in theindex.js
file where it saysawait config()
. Thisconfig
function is downloading a file from an S3 bucket where theipAddress
and other MongoDB info is stored. The problem is, I think, thatnconf
is trying to access those variables indb.js
before the file is fully downloaded. Any suggestions for that?