Wednesday, February 17

process management with pm2

Edit: There may be misleading stuff in these notes. In the end, I wound up going the simpler-to-explain route of just managing pm2 stuff as a user with a home directory and login shell. I don't exactly like this, but then ¯\_(ツ)_/¯

Here’s the tutorial I was writing all week.

I’m putting (hopefully) the last few pieces together in a tutorial on migrating hosted Parse applications to an instance of Parse Server running on a standalone box.

Parse is a “mobile backend as a service”, which is to say that it’s an API you can wire mobile apps up to, providing storage and authentication and a bunch of other stuff. Except it’s not going to be for much longer, because it’s shutting down after a Facebook acquisition.

Anyhow, the Parse folks (to their credit) have published an MIT-licensed Node.js version of this API, called Parse Server, which you can kinda run wherever, although the instructions are geared towards Heroku and other platformy stuff like that.

On an Ubuntu 14.04 system, I want to make sure that a parse-server process is started at system boot, running under a specific user called parse. There’s a Node-based process manager called PM2, which lets you do something like (assume I’m doing this all as root; sudo may complicate life):

# npm install -g pm2
# pm2 start parse-server

And then—this is pretty cool—you can say:

# pm2 save
# pm2 startup ubuntu

…and it’ll do something like this:

[PM2] Generating system init script in /etc/init.d/pm2-init.sh
[PM2] Making script booting at startup...
[PM2] -linux- Using the command:
      su -c "chmod +x /etc/init.d/pm2-init.sh && update-rc.d pm2-init.sh defaults"
 System start/stop links for /etc/init.d/pm2-init.sh already exist.
[PM2] Done.

Which is to say that it tries to write out a system-appropriate startup script which will resurrect the processes you saved. You can even specify a user and working homedir:

# pm2 startup ubuntu -u parse --hp /opt/parse-wrapper/

…which will set a user to run the startup script, and a home directory.

You can even write a JSON config file that will set environment variables and such, which I definitely need to do:

{
  "apps" : [{
    "name"        : "parse-wrapper",
    "script"      : "/usr/bin/parse-server",
    "watch"       : true,
    "merge_logs"  : true,
    "cwd"         : "/opt/parse-wrapper",
    "env": {
      "PARSE_SERVER_DATABASE_URI": "mongodb://user:pass@example.com/db?ssl=true",
      "PARSE_SERVER_APPLICATION_ID": "some_key",
      "PARSE_SERVER_MASTER_KEY": "some_key",
    }
  }]
}

The problem here, or at least the one I think I’m having, is that PM2 is saving its state in a $HOME/.pm2/. I checked, and it seems like I can just cp that directory into whatever desired location, but since I’m doing this in public, with impressionable nerds watching, it sure seems like there should be a less hacky approach to the problem. Also it seems to persist state I don’t want (like the user that owns the process, which is kind of the whole point).

If I can specify a homedir for generating the startup process, and in config files, shouldn’t I be able to do that when saving the process list and such?

There’s an entire deployment mechanism built into this thing, for some reason, which I think I could probably leverage to solve this problem, but come on.