Closed meglio closed 6 years ago
I would definitely recommend PM2, it’s a solid product that may be a little tricky to set up, but it does everything you may want (and may not know you want) from a process manager. That said, I’m always looking for new and better process management solutions. I wouldn’t be opposed to a daemon mode for PostGraphQL in the future if there is enough demand.
You could also look at Ubuntu Upstart which I’ve used before, or similar platform specific solutions.
With PM2, the quickest and simplest version that worked for me is:
pm2 start postgraphql -- postgres://pool_user:PA$$WORD@localhost:5432/dbname --route=/graphql --secret=$ECRET --development
Is there a better way to pass db password and secret token without revealing it in e.g. logs?
Also, an offtopic question, but still about starting postgraphql, maybe you can easily see where the error is in this pm2_postgraphql.json
file?
{
"name": "PostgrqphQL",
"script": "postgraphql",
"args": "postgres://pool_user:PA$$WORD@localhost:5432/dbname --route=/graphql --secret=$ECRET --development"
}
When configuring a pm2 service through a .json file, it does not seem to understand the arguments and instead tries to connect to the database as root (which fails).
Use environment variables to store secrets. Here’s a quick crash course on how to set environment variables: https://www.digitalocean.com/community/tutorials/how-to-read-and-set-environmental-and-shell-variables-on-a-linux-vps
Here’s the documentation I always use for PM2: http://pm2.keymetrics.io/docs/usage/application-declaration/
So a sample configuration may be:
{
"apps": [{
"name": "postgraphql",
"script": "./node_modules/.bin/postgraphql",
"args": "postgres://$DB_USER:$DB_PASS@localhost:5432/database --route graphql --secret $SECRET --development",
"instances": 1,
"exec_mode": "cluster",
"env": {
"DB_USER": "user",
"DB_PASS": "password",
"SECRET": "secret"
}
}]
}
I'll show what I've done:
The built file for production has private variables baked in. PM2 runs, restarts, etc. the built file.
"apps": [
{
"name": "api",
"script": "./build/dist/server.js"
}
],
Gulp is used as the CLI for running the build. Gulp has access to /.env
, which is git-ignored and used for private variables.
"scripts": {
"setup": "cp -n .env.example .env || true",
"dev": "gulp",
"eslint": "eslint ./src",
"test": "JWT_PRIVATE_KEY=foo NODE_ENV=test ./node_modules/mocha/bin/_mocha --opts ./spec/mocha.opts",
"build": "rimraf build && gulp build",
"start": "pm2 start ecosystem.json --env production",
"restart": "pm2 restart ecosystem.json",
"stop": "pm2 stop api",
},
import config from './webpack.config';
function onBuild (done, logLevel) {
return (err, stats) => {
if (err) {
console.log('Build threw error:', err);
} else if (logLevel === 'debug') {
console.log('[build stats]:', stats.toString());
}
if (done) {
done();
}
};
}
gulp.task('build-server', (done) => {
webpack(config).run(onBuild(done));
});
gulp.task('build', ['build-server']);
Webpack bundles the app src file. Webpack has an API for passing in env vars.
import env from 'gulp-env';
if (!process.env.PRIVATE_IP) {
env({file: './.env', type: 'ini'});
}
const {
NODE_ENV,
PRIVATE_IP,
REVERSE_PROXY_PRIVATE_IP,
PORT,
DB_PORT,
JWT_PRIVATE_KEY,
} = process.env;
...
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(NODE_ENV),
PRIVATE_IP: JSON.stringify(PRIVATE_IP),
REVERSE_PROXY_PRIVATE_IP: JSON.stringify(REVERSE_PROXY_PRIVATE_IP),
PORT: Number(PORT),
DB_PORT: Number(DB_PORT),
JWT_PRIVATE_KEY: JSON.stringify(JWT_PRIVATE_KEY),
},
}),
...
],
Postgraphql middleware in an Express.js app that references private vars on process.env
.
import postgraphql from 'postgraphql';
const {
NODE_ENV,
PRIVATE_IP,
REVERSE_PROXY_PRIVATE_IP,
PORT,
DB_PORT,
JWT_PRIVATE_KEY,
} = process.env;
api.use(postgraphql(`postgres://${REVERSE_PROXY_PRIVATE_IP}:${DB_PORT}`, ['terrafarm'], {
graphiql: NODE_ENV !== 'production',
jwtSecret: JWT_PRIVATE_KEY,
});
api.listen(PORT, () => {
console.log(`API listening at http://${PRIVATE_IP}:${PORT} 🌲`);
});
@calebmer : I want to start postgraphql server in background. so i am using this code in ecosystem.config .js as you suggested:
module.exports = {
"apps": [
{
"name": "postgraphql",
"script": "./node_modules/.bin/postgraphql",
"args": "postgres://$DB_USER:$DB_PASS@localhost:5432/database --route graphql --schema canny --default-role canny_anonymous --secret $SECRET --token canny.jwt_token --cors",
"instances": 1,
"exec_mode": "cluster",
"env": {
"DB_USER": "NAME",
"DB_PASS": "PASSWORD",
"SECRET": "secret"
}
}
]
}
In above code i have extra added --token canny.jwt_token --cors
.
i have schema name canny and using JWT Token canny.jwt_token for this but it give me error while i start it with pm2.
Error:
Error: Postgres token type "canny"."jwt_token" does not exist in your Postgres schema subset. Perhaps try adding schema "canny" to your list of introspected queries.
at Object.getPgTokenTypeFromIdentifier [as default] (/home/sourabh/canny/node_modules/postgraphql/build/postgraphql/schema/auth/getPgTokenTypeFromIdentifier.js:13:15)
at Object.<anonymous> (/home/sourabh/canny/node_modules/postgraphql/build/postgraphql/schema/createPostGraphQLSchema.js:49:65)
at step (/home/sourabh/canny/node_modules/tslib/tslib.js:121:27)
at Object.next (/home/sourabh/canny/node_modules/tslib/tslib.js:102:57)
at fulfilled (/home/sourabh/canny/node_modules/tslib/tslib.js:92:62)
at propagateAslWrapper (/usr/local/lib/node_modules/pm2/node_modules/async-listener/index.js:421:23)
at /usr/local/lib/node_modules/pm2/node_modules/async-listener/index.js:458:70
at process._tickDomainCallback [as _tickCallback] (internal/process/next_tick.js:129:7)
but when i run below command its works fine but i have to run this in background:
postgraphql -c \"postgres://USERNAME:PASSWORD@localhost/canny_dev\" --schema canny --default-role canny_anonymous --secret SECRET --token canny.jwt_token --cors
Please look into this. Thanks.
In args
above you have postgres://$DB_USER:$DB_PASS@localhost:5432/database
; but in the command line you replace database
with canny_dev
@benjie: I just give reference. I have replaced database
with canny_dev
while trying this code . canny_dev
is my DB name.
Well, not sure how much I can help if you don't provide the actually config; but it might be that you're lacking -c
before the database URL right at the beginning of args
@benjie : Thanks. yes i have skipped -c
with this option its works. but for this i have to pass direct DB_USER and DB_PASS in above url. Its not take it from env
config.
Error:
error: role "$DB_USER" does not exist
Thanks again.
For those interested, I just blogged about using pm2 and postgraphile.
@omatrot -- I would love to read this but I am clicking on the link and it just gets me to a blank page? Not sure what I am doing wrong..
@sjmcdowall Yeah sorry the link was incorrect. Now it should work.
Nice! ALthough this seems a bit off topic -- but have you tried instances > 1 and how does that perform? In fact, how performant is postgraphile in general? Any gut feel for V4 with all the improvements?
You can read about performance here: https://www.graphile.org/postgraphile/performance/
(I only added that page a few days ago)
The solution using ecosystem.config does not work for me when using a plugin, see: https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/issues/38
Does anyone fancy writing up a guide for the website on how to use PM2 in production?
[semi-automated message] We try and keep the open issues to actual issues (bugs, etc); this seems like more of a discussion right now, so I'm closing it but please feel free to keep discussing it below 👍
Hi. To make the server run in background and restart on failure and start automatically on server reboot, what would be the solution?
I read about PM2 - is it suitable, or is there an easier way?