Giter Club home page Giter Club logo

final-pm's Introduction

FinalPM

Build Status Coverage Status David GitHub package version npm

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

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.

Features

  • Easy configuration in either JSON or JS
  • Graceful restarting of applications by default
  • Clean process lifecycle management without the possibility of edge cases or race conditions
  • Simple and Safe

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 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.

Quick Start

Install FinalPM with your preferred node package manager and make sure it is working:

yarn global add final-pm
final-pm --help

Create a bare-bones configuration process-config.json:

{
    "applications": [{
        "name": "myApp",
        "run": "app.js"
    }]
}

And a simple application app.js:

require('http').createServer((req, res) => {
    console.log(req.url);
    res.end("Hello World!");
}).listen(5555);

// If the master asks us to stop, do so
process.on('SIGINT', () => {
    console.log("Goodbye World!");

    // Implicitly calls server.close, then disconnects the IPC channel:
    require('cluster').worker.disconnect();
});

Once you have done so, in the same directory, run final-pm start myApp:

[...]
[INFO ] [Action] Start 1 process...
[INFO ] [Action] Success

If you navigate to http://localhost:5555/ now, you should be greeted with "Hello World!".

You can watch your app's console output with final-pm log -f or check the log.txt file created in the same directory:

[...]
[LOG  ] [10:24:36 AM] [myApp/0] [STDOUT] /
[LOG  ] [10:24:36 AM] [myApp/0] [STDOUT] /favicon.ico

Now, because we are expecting a heavy load on our application, we may be inclined to start multiple instances of it. For this we will modify process-config.json to look like this:

{
    "applications": [{
        "name": "myApp",
        "run": "app.js",
        "instances": 4
    }]
}

Use final-pm scale myApp to make FinalPM automatically figure out how many new processes to start:

[INFO ] [Config] myApp{instances} updated
[INFO ] [Action] Start 3 processes...
[INFO ] [Action] Success

final-pm show will show an overview of all currently running processes. There you may notice that one of our processes (myApp/0) has a little indicator saying "(old)" behind its name. This means that the process was started using an older configuration (before we added instances: 4).

In our case this is not important, since the new configuration doesn't affect the behavior of our processes at all. But let's just replace it with a new process to get rid of that pesky "(old)":

final-pm restart myApp/0

[INFO ] [Action] Start 1 process...
[INFO ] [Action] Success

What this will do is start a new process for myApp/0, then stop the old process once the new instance has become ready. Zero Downtime. Also restart is really just an alias for start, since FinalPM always stops old processes once new instances of them become ready. Instead of scale myApp we also could have just used restart myApp from the get-go, arriving at same final result of 4 processes without any old configurations.

We have hardly scratched the surface of what FinalPM can do, though this is the end of this quick start guide. For further reading check final-pm --help-usage, final-pm --help-configuration, final-pm --help-generations etc.

To stop the daemon and kill all remaining processes, do:

final-pm --kill

Documentation for the CLI/architecture can be found here. The same information is also accessible via final-pm --help-all.

Also check out the /examples directory. If you have cloned this repository locally, the easiest way to start playing around with them is cd examples && final-pm start all.

TODO

  • More test cases, especially for negatives
  • Documentation for using FinalPM programmatically / Daemon API
  • Support arbitrary processes (non-node)

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)
Lines of Code <4,000 >20,000
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.

final-pm's People

Contributors

laino avatar realdolos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

realdolos

final-pm's Issues

Arguments mismatch for stop: "value" must be a number

Hello @laino! It looks like there's an issue when downscaling an app:

// conf.js
module.exports = {
  applications: [
    {
      "name": "foo",
      "run": "foo.js",
      "instances": 2,
      "ready-on": "message"
    },
  ]
};
// foo.js
process.send('ready');
setTimeout(() => {}, 999999999);
final-pm -c conf.js start foo
[INFO ] [Daemon] Starting Daemon
[INFO ] [Config] foo added
[INFO ] [Action] Start 2 processes...
[INFO ] [Action] Success

Now change the number of instances in the config file to just 1 and run scale.

final-pm -c conf.js scale foo
[INFO ] [Config] foo{instances} updated
[INFO ] [Action] Stop 1 process...
[ERROR] [CLI] Arguments mismatch for all: Arguments mismatch for stop: "value" must be a number
final-pm -c conf.js show

image

Any ideas?

Add dependencies metric in pm2 comparison

You already compare LOC, however that's only part of the truth... The actual LOC that will be (potentially) running on one's system are not just the lines from the projects but also from all of those dependencies.

The node "community" has a tendency to add a metric (or maybe even imperial) shitton of dependencies to everything they code... libraries of quite varying[0] quality which in turn pull in even more libraries of varying quality.

Furthermore, there were finally some blogs pointing out how many of the node community will often blinding import third party code, commonly the minified and transpiled "release" versions that even cannot be audited, without anybody ever considering the possibility of an evil actor[1].

As such, it is preferable that:

  • Any and all dependencies have merit and purpose being there. [2]
  • Authors, such as yourself, are aware of the pros and cons of dependencies and vet any new (and occasionally re-vet old) dependencies
  • Authors make it known that they are.

In the end, I[4] gotta trust you as an author[5].

[0] "varying" in this context obviously means inefficient, insecure and generally crappy.
[1] Putin himself hacking your node app to change the outcome of the election in your country.
[2] aka. you're not too lazy or unskilled to google String.prototype.padEnd on MDN[3]
[3] the npm leftpad/padleft/padgenericfromtheleftexceptwhenpassingaconfigurationobjecttopadrightinstead packages are serious quality softwares that should be included in every node project
[4] properly tinfoiled at almost all times
[5] I kinda trust you so far, even tho you're from Bavaria.

Write daemon's PID to file on startup

Helllo @laino! I use systemd to launch final-pm on system boot and while it's working fine (systemd is able to "guess" the just launched daemon's PID), it would be great if final-pm wrote the daemon's PID into a file (~/.final-pm/daemon.pid maybe?) once it's up. It would make the setup more robust. What do you think?

Arguments mismatch for follow: "value" with value "all"

Hello @laino! It looks like there's an issue when trying to log -f all of the available apps. I assume all should be supported here as well. If not, please consider this a feature request :).

final-pm log -f all
[ERROR] [CLI] Arguments mismatch for follow: "value" with value "all" matches the inverted is not "all" pattern

Windows support?

I installed final-pm on Windows. I met some errors.

The first error

The examples is not published with npm package (which is good), so I have to comment out export.examples in cli-args.js.

The second error is not able to start daemon

node_modules\.bin\final-pm start app -v
[DEBUG] [Connection] Connecting to ws+unix://C:\Users\me\.final-pm\daemon.sock
[INFO ] [Daemon] Starting Daemon
[ERROR] [CLI] spawn D:\proj1\node_modules\final-pm\bin\daemon ENOENT

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.