Nodemon: Reproducible: Error: listen EADDRINUSE :::3000

Created on 5 Dec 2018  路  34Comments  路  Source: remy/nodemon

  • nodemon -v: 1.17.3
  • node -v: v9.11.2
  • Operating system/terminal environment: macOS High Sierra Version 10.13.6 (17G65) (Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64)
  • Command you ran: complicated; see below

Expected behaviour

  • Clean restart of app
  • Listening on port again after a short time

Actual behaviour

  • The following error
events.js:167
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE :::3000
    at Server.setupListenHandle [as _listen2] (net.js:1328:14)
    at listenInCluster (net.js:1376:12)
    at Server.listen (net.js:1463:7)
    at Function.listen (/opt/code/node_modules/express/lib/application.js:618:24)
    at Object.<anonymous> (/opt/code/server.js:82:5)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at loader (/opt/code/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/opt/code/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
Emitted 'error' event at:
    at emitErrorNT (net.js:1355:8)
    at process._tickCallback (internal/process/next_tick.js:63:19)
    at Function.Module.runMain (internal/modules/cjs/loader.js:746:11)
    at Object.<anonymous> (/opt/code/node_modules/babel-cli/lib/_babel-node.js:154:22)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
    at Module.load (internal/modules/cjs/loader.js:612:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
    at Function.Module._load (internal/modules/cjs/loader.js:543:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)
[nodemon] app crashed - waiting for file changes before starting...

Steps to reproduce

  1. Download nodemon-test.zip
  2. decompress zip
  3. open shell in decompressed dir
  4. Run make start-test

If applicable, please append the --dump flag on your command and include the output here ensuring to remove any sensitive/personal details or tokens.

remy working on it

Most helpful comment

I've been working on this today. The problem is in the ps tree implementation I took from node-kill-tree - basically it doesn't work across all docker images.

I'm refactoring the pstree.remy so that it will work.

It's because ps _and_ how processes are killed, work slightly differently in the alpine flavour of linux.

All 34 comments

  • Makefile
default: start-test
.PHONY: start-test start-docker system-config dist

start-test:
    ./start.sh

start-docker:
    docker stop nodemon-test || true
    # docker rm nodemon-test || true
    docker run -it --rm \
        --name nodemon-test \
        -p3099:3000 \
        --volume "$(shell pwd)":/opt/code \
        --workdir /opt/code \
        node:10.5.0-alpine \
        /opt/code/docker_init

system-config:
    @echo "" > system-config.log 2>&1 || true
    @echo "\n\n## nodemon -v\n" >> system-config.log
    nodemon -v >> system-config.log 2>&1 || true
    @echo "\n\n## node -v\n" >> system-config.log
    node -v >> system-config.log 2>&1 || true
    @echo "\n\n## uname -v\n" >> system-config.log
    uname -v >> system-config.log 2>&1 || true
    @echo "\n\n## port installed\n" >> system-config.log
    port installed >> system-config.log 2>&1 || true
    @echo "\n\n## npm ls\n" >> system-config.log
    npm ls >> system-config.log 2>&1 || true

dist:
    mkdir -p dist
    rm dist/nodemon-test.zip || true
    ls | grep -v node_modules | grep -v dist | grep -v pack.sh | zip -@ dist/nodemon-test.zip
  • package.json
{
  "name": "nodemon-test",
  "version": "0.0.1",
  "private": true,
  "entry": "./server.js",
  "nodemonConfig": {
    "verbose": true,
    "events": {
      "crash": "echo \"[nodemon] crashed at $(date)\";",
      "start": "echo \"[nodemon] started at $(date)\";",
      "restart": "echo \"[nodemon] restarted at $(date)\";"
    }
  },
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-core": "^6.25.0",
    "babel-plugin-transform-es2015-destructuring": "^6.23.0",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
    "babel-plugin-transform-es2015-spread": "^6.22.0",
    "babel-plugin-transform-object-rest-spread": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "chai": "^4.0.2",
    "chai-http": "^4.2.0",
    "eslint": "^4.19.1",
    "eslint-config-airbnb": "^17.0.0",
    "eslint-plugin-import": "^2.12.0",
    "eslint-plugin-jsx-a11y": "^6.0.3",
    "eslint-plugin-react": "^7.9.1",
    "faker": "^4.1.0",
    "mocha": "^3.4.2",
    "sinon": "^4.4.5",
    "sinon-chai": "^3.2.0",
    "webpack": "^4.12.0",
    "webpack-cli": "^3.0.8",
    "yargs": "^12.0.1"
  },
  "dependencies": {
    "aws-sdk": "^2.207.0",
    "body-parser": "^1.18.2",
    "bunyan": "^1.8.12",
    "card-detector": "0.0.4",
    "cookie-parser": "^1.4.3",
    "cors": "^2.8.4",
    "elasticsearch": "^15.0.0",
    "express": "^4.16.2",
    "express-bunyan-logger": "^1.3.2",
    "express-jwt": "^5.3.1",
    "expresss": "0.0.0",
    "google-libphonenumber": "^3.0.10",
    "grpc": "^1.16.1",
    "handlebars": "^4.0.11",
    "http-aws-es": "^6.0.0",
    "i18n-iso-countries": "^3.7.3",
    "inflection": "^1.12.0",
    "joi": "^13.4.0",
    "joi-phone-number": "^2.0.1",
    "jsdom": "^11.12.0",
    "jsonwebtoken": "^8.1.1",
    "lodash": "latest",
    "lodash.isempty": "^4.4.0",
    "maxmind": "^2.7.0",
    "moment": "^2.22.0",
    "node-2fa": "^1.1.2",
    "node-fetch": "^2.0.0",
    "node-jose": "^0.11.0",
    "npm": "^6.1.0",
    "qs": "^6.5.1",
    "request": "^2.87.0",
    "soap": "^0.24.0",
    "usps-web-tools-node-sdk": "^0.5.0",
    "uuid": "^3.2.1",
    "wordpress-hash-node": "^1.0.0",
    "xml2js": "^0.4.19",
    "yamlparser": "0.0.2"
  }
}
  • server.js
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const express = require('express');
const fs = require('fs');
const path = require('path');
const parse = require('querystring').parse;

const PORT = process.env.PORT || 3000;
const app = express();

app.use(bodyParser.raw({ type: '*/*' }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.enable('trust proxy');

const loggingMiddleware = require('express-bunyan-logger')({ // eslint-disable-line global-require
  obfuscate: [
    'body.data.attributes.payment_source.account_number',
    'body.data.attributes.payment_source.cvv',
    'body.data.attributes.account_number',
    'body.data.attributes.cvv',
    'req-headers.authorization',
  ],
  includesFn: (req, res) => ({
    user: req.user && req.user.sub,
    'created-id': res.newId,
  }),
});

app.use((req, res, next) => {
  if (req.path === '/.health') {
    next();
  } else {
    loggingMiddleware(req, res, next);
  }
});

app.use((req, res, next) => {
  res.set('X-Request-Id', req.id);
  res.set('Cache-Control', 'no-cache, no-store, must-revalidate');
  res.set('Pragma', 'no-cache');
  res.set('X-Frame-Options', 'SAMEORIGIN');
  res.set('Content-Type', 'application/vnd.api+json');

  if (req.body.length) {
    req.body = req.body.toString();
  }

  if (req.body.length) {
    const ct = req.get('content-type');

    if (ct.indexOf('application/x-www-form-urlencoded') != -1) {
      req.body = parse(req.body);
    } else {
      req.body = JSON.prase(req);
    }
  }

  next();
});

app.get('/', (req, res) => res.send(''));

// Catch all routes that don't match (404)
app.use((req, res, next) => {
  next(Object.assign(new Error('Not Found'), { status: 404 }));
});

// Error handler
app.use((err, req, res, next) => {
  res.set('Access-Control-Allow-Origin', '*');

  if (err) {
    console.log({ error: err.stack, req_id: req.id }, 'Unexpected error.');
    res.status(500);
    res.send(Object.assign(new Error('Internal Error'), { status: 500 }));
  } else {
    next();
  }
});

app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`);
  // setTimeout(() => {
  //   console.log(`touch ${__filename}`);
  //   fs.closeSync(fs.openSync(__filename, 'w'));
  // }, 1000);
});
  • start.sh
#!/bin/sh

PARENT_ID=$$

background_f() {

  # However long you need for the server to be listening
  for i in {1..8}
  do
    sleep 10
    echo
    echo "## $(( 80 - (i * 10) )) Seconds to 'touch server.js'"
    echo
  done

  echo
  echo "## touch server.js"
  echo
  touch server.js

  # However long it takes to reproduce the issue (or not ):
  for i in {1..4}
  do
    sleep 10
    echo
    echo "## $(( 40 - (i * 10) )) Seconds to 'kill -INT \$PID'"
    echo
  done

  echo "## CTRL+C server (you may have to CTRL+C yourself...)"
  echo
  kill -INT $PARENT_ID || true
}

background_f &
BACKGROUND_ID=$!
echo "subprocess ID $ID"
jobs

make start-docker | tee run.log

kill -INT $BACKGROUND_ID || true

This setup is so verbose because I took our project and simplified it for reproducibility as much as was a bit easy. I'd like to see how reproducible this actually is on other systems.

Same behaviour here, nodemon crashes with Error: listen EADDRINUSE :::8085 upon automatic restart or after Ctrl + C stop and subsequent start.
Node 10.7.0
macOS Mojave 10.14.1

@sofiia-hlyniana this is a docker + nodemon issue. Are you saying you're seeing the same?

@remy Sorry, didn't notice docker was also there. I'm not using it, but I see the same error as described using nodemon only. However, I still can create another issue if it is critical to do so.

@sofiia-hlyniana no problem. If you can, and if you can include code that can replicate the problem then it makes it marginally easier to debug 馃憤

Also running into this error, after upgrading

Also have this issue after recent upgrade.

We're also seeing this issue when using Docker. We're using nodemon v1.18.7.

Experiencing this issue also, nodemon v1.18.7

This was previously working fine on v1.17.2.

However after upgrading to v1.18.7, this issue started happening. Tried to downgrade again to v1.17.2, it was not enough - the bug was still present.

It seems that the pstree.remy dependency had remained upgraded (to v1.1.2) from v1.18.7 - due to the semver.

Using v1.17.2, and adding the following workaround in package.json (for those using yarn) seems to have fixed it:

 "resolutions": {
   "nodemon/pstree.remy": "1.1.0"
 }

@avaly thanks! that works

 "resolutions": {
   "nodemon/pstree.remy": "1.1.0"
 }

How does one do this for npm?

@servel333 just add the that snippet to your package.json

That is a duplicated of https://github.com/remy/nodemon/issues/1477 which is being discussed already and we are trying to find the fix.

@servel333 the solution works only with yarn I believe not with npm
With npm, you can downgrade to the version 1.13.3

I also confirmed that using v1.18.6, with the yarn resolution hack from above, works fine.

I also confirm that using v1.18.6, with the yarn resolution hack, works fine 馃憦

@zefexdeveloper Some people in this thread have said they can reproduce this without Docker. Does that still make this a duplicate?

@servel333 I came to the same root cause pstree.remy. So I guess the fix will correct both issue ;)

@servel333 Judging by the main subject, yes, it's duplicated, people saying that they are having the same issue without Docker is just a consequence, but anyway, we are just trying to find a solution anyway :smile:

This is splitting hairs, but technically my subject doesn't mention Docker... @zefexdeveloper :)

1.13.3 was the last working version for me

I've been working on this today. The problem is in the ps tree implementation I took from node-kill-tree - basically it doesn't work across all docker images.

I'm refactoring the pstree.remy so that it will work.

It's because ps _and_ how processes are killed, work slightly differently in the alpine flavour of linux.

Live fix in [email protected] (core change in pstree.remy鈥gain).

Still having the same issue with 1.1.8 in node:8.12-alpine

also with node:10-alpine

@timini are you able to debug?

Seems to work with node:10 but not node:10-alpine

@remy What do you want to know? It seems the SIGUSR2 is never emitted on process when using alpine docker image.

what do I want to know

Ideally what to change to fix it.

Can you give me a clue where to start looking? Bearing in mind I have no existing knowledge of the pstree package

Equally I have know existing knowledge as to the specifics of your dev environment鈥ou've not provided any example code to replicate with so there's no real point in trying to guess.

pstree package is very small: https://github.com/remy/pstree/blob/master/lib/index.js

But you're going to have a better idea if you look at nodemon's source in run.js and look for where it sends the kill signal - and list out the PIDs that are going to be shutdown. My guess is that it's not including the hanging process. Another guess (since I tested with node:alpine), is that there's something to do with your code and the way you're running your software that's going to expose the _real_ bug. But again, you've not offered anything so this original issue by the OP has been closed.

@remy & @timini My test case uses the Docker image node10-alpine and it works fine with the latest version.

@timini sorry for the silly questions but are you sure you:

  1. deleted your package-lock.json
  2. npm install
  3. docker build .
Was this page helpful?
0 / 5 - 0 ratings

Related issues

medoix picture medoix  路  4Comments

binarykitchen picture binarykitchen  路  5Comments

endquote picture endquote  路  4Comments

Makoehle picture Makoehle  路  3Comments

Autre31415 picture Autre31415  路  4Comments