Paris.js #53

Gérer ses serveurs

de développement et de tests avec PM2

@alexisjanvier

@marmelab

Advanced, production process manager for Node.js

http://pm2.keymetrics.io/

Un projet classique

  • une API d'administration (Koa)
  • une API public (Koa)
  • une interface d'administration (ng-admin)
  • une application public (React/Redux)

https://github.com/marmelab/javascript-boilerplate

Développement

- un serveur Node pour les deux API

- un webpack-dev-server pour l'administration

et l'application public 

TESTS

- un serveur Node pour les deux API

- un serveur de statics (http-server) pour l'administration

et l'application public 

Lancement ""à la mano""

$: ./node_modules/.bin/nodemon --watch api --watch config src/api/index.js 
$: ./node_modules/.bin/webpack-dev-server --content-base=build \
--devtool=cheap-module-inline-source-map --hot --inline --quiet --progress

webpack-dev-server

node (nodemon)

bof ...

makefile

webpack.PID:
	@./node_modules/.bin/webpack-dev-server \
		--content-base=build \
		--devtool=cheap-module-inline-source-map \
		--hot \
		--inline \
		--quiet \
		--progress \
		& echo "$$!" > webpack.PID

stop-frontend-dev: webpack.PID
	@kill `cat $<` && rm $<
	@echo "Webpack server stopped"

run-api-dev: server.PID
server.PID:
	@./node_modules/.bin/nodemon --watch api --watch config api/index.js \
        & echo "$$!" > server.PID
stop-api-dev: server.PID
	@kill `cat $<` && rm $<
	@echo "Node server stopped"

run-dev: run-frontend-dev run-api-dev
stop-dev: stop-frontend-dev stop-api-dev

AVEC PM2

// config/pm2-servers/dev.json
{
  "apps" : [{
    "name"       : "bpm_api-dev",
    "script"     : "./src/api/index.js",
    "watch"      : ["./src/api", "./src/isomorphic", "config"],
    "instances"   : 1,
    "autorestart" : true,
    "env": {
        "NODE_ENV": "development",
    }
  }, {
    "name"       : "bpm_frontend-dev",
    "script"     : "./node_modules/.bin/webpack-dev-server",
    "args"       : [
        "--content-base=build",
        "--devtool=cheap-module-inline-source-map",
        "--hot",
        "--inline",
        "--quiet",
        "--progress"
    ],
    "instances"   : 1,
    "autorestart" : true,
    "env": {
        "NODE_ENV": "development",
    }
  }]
}
# makefile

run-dev:
	@node_modules/.bin/pm2 start ./config/pm2_servers/dev.json
stop-dev:
	@node_modules/.bin/pm2 delete ./config/pm2_servers/dev.json

Et beaucoup d'autres features : restart, logs, monitoring, ...

Lancement des tests fonctionnels

// config/pm2-servers/test.json

{
  "apps" : [{
    "name"       : "bpm_api-test",
    "script"     : "./src/api/index.js",
    "exec_mode"  : "fork",
    "env": {
      "NODE_ENV": "test",
      "NODE_PORT": 3010
    }
  },
  {
    "name"       : "bpm_frontend-test",
    "script"     : "./node_modules/.bin/http-server",
    "args"       : ["./build", "-p 8081", "--silent"],
    "exec_mode"  : "fork",
    "env": {
        "NODE_ENV": "test",
        "NODE_PORT": 3020
    }
  }]
}
# Makefile

test-frontend-functional: reset-test-database
	NODE_ENV=test make load-fixtures
	@make build-test
	@node_modules/.bin/pm2 start ./config/pm2_servers/test.json
	@node_modules/.bin/nightwatch --config="./e2e/frontend/nightwatch.json"
	@node_modules/.bin/pm2 delete ./config/pm2_servers/test.json

... et une API pour utiliser pm2 directement dans les tests

import pm2 from 'pm2';

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.start({
    script    : 'app.js',         // Script to be run
    exec_mode : 'cluster',        // Allow your app to be clustered
    instances : 4,                // Optional: Scale your app by 4
    max_memory_restart : '100M'   // Optional: Restart your app if it reaches 100Mo
  },(err, apps) => {
    pm2.disconnect();
  });
});

global Vs project

# ~/.pm2
.
├── conf.js
├── dump.pm2
├── logs
│   ├── bpm-api-dev-error-0.log
│   ├── bpm-api-dev-out-0.log
│   ├── bpm-frontend-dev-error-1.log
│   └── bpm-frontend-dev-out-1.log
├── module_conf.json
├── pids
├── pm2.log
├── pm2.pid
├── pub.sock
├── rpc.sock
└── touch

2 directories, 12 files
$: PM2_HOME='.myProject' ./node_modules/.bin/pm2 start ./config/pm2_servers/test.json

MERCI