RealDolos / final-pm

Finally a solid process manager. Currently WIP.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FinalPM

Finally a solid process manager. Never unintentionally kill your application in production again.

Getting started

The project is currently in the works, but you can already check out some

Documentation

and Examples

Why?

The current state of node.js process managers is terrible. Besides most of them trying to be 20 things at once, and not even being decent at any of them, there is hardly one being half as reliable as you'd expect of a core component.

Comparison Between Process Managers

Feature FinalPM PM2
Basic Process Management (start / stop / kill) Yes Yes
Graceful Starts/Restarts/Stops Yes Possibly (1)
FSM-Style Process Lifecycles Yes No (2)
Safe by Design Yes No (3)
Helpful and Early Errors Always (4) Sometimes
Clean Configuration Yes No (5)
Metrics and a boatload of other features No Yes (6)
  1. PM2 may default to ungracefully restarting/stopping applications if some conditions are not met, for instance: your application isn't considered online yet, you want to use the ready message, or you're using the fork mode. FinalPM on the other hand will always complete a clean lifecycle for each started process.
  2. PM2 handles process state transitions by means of imperative, callback based code, making it hard to reason about the effects of multiple concurrent actions. FinalPM separates command/signal handlers for each process state and models state transition in an atomic fashion, thus eliminating edge cases.
  3. In many cases PM2 will naively perform dangerous actions which may result in downtime.
  4. FinalPM is very strict in what it will accept, aborting with helpful error messages if anything with your configuration or command looks fishy. FinalPM will never try to assume anything about what you meant to do, and not default to any potentially harmful action. We believe not accidentally killing your production application is preferable to ease of use.
  5. FinalPM treats all configuration keys the same. Each key can be provided by either a configuration file, an environment variable or a program argument. PM2 tends to have different names for the same configuration keys across environment variables and configuration files, and some closely related keys are even spread out across multiple places.
  6. We don't believe any of these belong directly in a process manager, but FinalPM won't stand in your way of adding such things to your application. Due to only focusing on the basics, FinalPM's codebase is smaller by an order of magnitude.

Design Philosophy

Most of the complicated logic resides outside of the daemon itself, either sandboxed into other processes (Loggers) or moved up the chain (clients). The daemon should only support a minimal set of generic functions, which can be used to create higher level interfaces, such as the CLI.

Process state is managed in https://github.com/laino/final-pm/tree/master/doc#generations, which are exclusively managed by synchronous code, asynchronous operations such as timeouts being hidden by the Process object and their state robustly managed there. This avoids weird or buggy behavior due to multiple asynchronous operations creating race conditions, from which many process managers suffer.

Taken together these design decisions should create an extremely robust daemon process on which your application can rely. A crashing daemon process means crashing applications - A component meant to make your application more reliable should avoid introducing additional points of failure.

A note on PM2

This section is mostly a rant I wrote after losing a night's worth of sleep when I made the mistake of trying to switch to pm2 in production.

PM2 is the most popular, and as anyone unfortunate enough to have to read its source code will quickly discover, also a mess of spaghetti code, inconsistencies and plain weirdness. The aforementioned pitiful souls being basically everyone with a valid use case for a process manager, who had to resort to reading source code because of lacking documentation or undocumented behavior.

Want to set up graceful reloads for your web app, so your user's downloads don't get interrupted when you deploy? Not happy with the default behavior of PM2 considering your process online when it starts to listen on a socket? Good luck.

Because the documentation won't help you and instead will confuse you even further by being outdated, wrong, or having 2 chapters on what is apparently the same thing, except with a completely different description.

Good luck figuring out how to configure the thing, because only half the config can be done in ecosystem.config.js / environment variables each, even for things closely related to each other. For those still searching, here's the config values for graceful reloads:

# ecosystem.apps || ENV

kill_timeout     || PM2_KILL_TIMEOUT                # How long PM2 waits after SIGINT before sending SIGKILL
listen_timeout   || PM2_GRACEFUL_LISTEN_TIMEOUT     # How long PM2 waits for the 'listening' event or 'ready' message before considering your process online anyways (WHY?)
(NONE)           || PM2_GRACEFUL_TIMEOUT            # How long PM2 waits after sending 'shutdown' (graceful reload) before shutting down your process normally

# DANGER ZONE: SETTING THESE TO 'true' OR 'fork' (default) respectively will silently cause PM2 to un-gracefully restart your application [1]:
wait_ready       || (NONE)                          # true or false, If true, PM2 will wait for process.send('ready') instead of waiting for the 'listening' event.
exec_mode        || (NONE)                          # 'fork' or 'cluster'. 

1: Comment

Graceful restarts in 'fork' mode are nearly impossible with node's default APIs. PM2 only fails to communicate this anywhere by - for instance - rejecting such configuration and failing with an error early. Graceful restarts and wait_ready just don't work together in PM2 pretty much because.

Don't trust a process manager that can't get basic stuff like that right, will send you down a goose chase with a completely wrong error message and a lack of documentation, then will reveal to you that no, you can't have graceful reloads with process.send('ready') actually.

About

Finally a solid process manager. Currently WIP.


Languages

Language:JavaScript 100.0%