Cross-platform service management made easy.
sudo serviceman add --name foo ./serve.js --port 3000
Success: "foo" started as a "launchd" SYSTEM service, running as "root"
Because it sucks to debug launchctl, systemd, etc.
Also, I wanted a reasonable way to install Telebit on Windows. (see more in the More Why section below)
--user
(Default)
sytemctl --user
)launchctl
)HKEY_CURRENT_USER/.../Run
)--system
(Default for root
)
sudo sytemctl
)sudo launchctl
)The basic pattern of usage:
sudo serviceman add --name "foobar" [options] [interpreter] <service> [--] [service options]
sudo serviceman start <service>
sudo serviceman stop <service>
sudo serviceman list --all
serviceman version
And what that might look like:
sudo serviceman add --name "foo" foo.exe -c ./config.json
You can also view the help:
serviceman add --help
User services start on login.
System services start on boot.
The default is to register a user services. To register a system service, use sudo
or run as root
.
You can install serviceman
directly from the official git releases with webi
:
Mac, Linux:
curl -sL https://webinstall.dev/serviceman | bash
Windows 10:
curl.exe -sLA "MS" https://webinstall.dev/serviceman | powershell
You can run this from cmd.exe or PowerShell (curl.exe is a native part of Windows 10).
There are a number of pre-built binaries.
If none of them work for you, or you prefer to build from source, see the instructions for building far down below.
curl -fsSL "https://rootprojects.org/serviceman/dist/$(uname -s)/$(uname -m)/serviceman" -o serviceman
chmod +x ./serviceman
Windows
mkdir %userprofile%\bin
move serviceman.exe %userprofile%\bin\serviceman.exe
reg add HKEY_CURRENT_USER\Environment /v PATH /d "%PATH%;%userprofile%\bin"
All Others
sudo mv ./serviceman /usr/local/bin/
sudo serviceman add --name <name> <program> [options] [--] [raw options]
# Example
sudo serviceman add --name "gizmo" gizmo --foo bar/baz
Anything that looks like file or directory will be resolved to its absolute path:
# Example of path resolution
gizmo --foo /User/me/gizmo/bar/baz
Use --
to prevent this behavior:
# Complex Example
sudo serviceman add --name "gizmo" gizmo -c ./config.ini -- --separator .
For native Windows programs that use /
for flags, you'll need to resolve some paths yourself:
# Windows Example
serviceman add --name "gizmo" gizmo.exe .\input.txt -- /c \User\me\gizmo\config.ini /q /s .
In this case ./config.ini
would still be resolved (before --
), but .
would not (after --
)
serviceman
from your project directory, just as you would run it normally
--name <service-name>
and --workdir <project directory>
--
in front of arguments that should not be resolved as paths
--
as an argument, such as -- --foo -- --bar
# Example of a / that isn't a path
# (it needs to be escaped with --)
sudo serviceman add dinglehopper config/prod -- --category color/blue
sudo journalctl -xef --unit <NAME>
sudo journalctl -xef --user-unit <NAME>
When you run serviceman add
it will either give you an error or
will print out the location where logs will be found.
By default it's one of these:
~/.local/share/<NAME>/var/log/<NAME>.log
/opt/<NAME>/var/log/<NAME>.log
You set it with one of these:
--logdir <path>
(cli)"logdir": "<path>"
(json)Logdir: "<path>"
(go)If anything about the logging sucks, tell me... unless they're your logs (which they probably are), in which case you should fix them.
That said, my goal is that it shouldn't take an IT genius to interpret why your app failed to start.
serviceman add --dryrun <normal options>
serviceman run --config <special config>
One of the most irritating problems with all of these launchers is that they're terrible to debug - it's often difficult to find the logs, and nearly impossible to interpret them, if they exist at all.
The config files generate by serviceman
are simple, template-generated and
tested, and therefore gauranteed to work - if your
application runs with the parameters given, which is big 'if'.
serviceman
tries to make sure that all necessary files and folders
exist and give clear error messages if they don't (be sure to check the logs,
mentioned above).
There's also a run
utility that can be used to test that the parameters
you've given are being interpreted correctly (absolute paths and such).
serviceman run --config ./conf.json
Where conf.json
looks something like
For Binaries:
{
"title": "Demo",
"exec": "/Users/me/go-demo/demo",
"argv": ["--foo", "bar", "--baz", "qux"]
}
For Scripts:
Scripts can't be run directly. They require a binary interpreter
- bash, node, ruby, python, etc.
If you're running from the folder containing ./demo.js
,
and node.exe
is in your PATH, then you can use executable
names and relative paths.
{
"title": "Demo",
"interpreter": "node.exe",
"exec": "./bin/demo.js",
"argv": ["--foo", "bar", "--baz", "qux"]
}
That's equivalent to this:
{
"title": "Demo",
"name": "demo",
"exec": "node.exe",
"argv": ["./bin/demo.js", "--foo", "bar", "--baz", "qux"]
}
Making add
and run
take the exact same arguments is on the TODO list.
The fact that they don't is an artifact of run
being created specifically
for Windows.
If you have gripes about it, tell me. It shouldn't suck. That's the goal anyway.
Windows binaries can be built either for the console or the GUI.
When they're built for the console they can hide themselves when they start. They must open up a terminal window.
When they're built for the GUI they can't print any output - even if they're started in the terminal.
This is why there's a Debug version for the windows binaries - so that you can get your arguments correct with the one and then switch to the other.
There's probably a clever way to work around this, but I don't know what it is yet.
Windows doesn't have a userspace daemon launcher. This means that if your application crashes, it won't automatically restart.
However, serviceman
handles this by not directly adding your application
to HKEY_CURRENT_USER/.../Run
, but rather installing a copy of itself
instead, which runs your application and automatically restarts it whenever it
exits.
If the application fails to start serviceman
will retry continually,
but it does have an exponential backoff of up to 1 minute between failed
restart attempts.
See the bit on serviceman run
in the Debugging section up above for more information.
git clone https://git.coolaj86.com/coolaj86/go-serviceman.git
pushd ./go-serviceman
go generate -mod=vendor ./...
Windows:
go build -mod=vendor -ldflags "-H=windowsgui" -o serviceman.exe
Linux, MacOS:
go build -mod=vendor -o /usr/local/bin/serviceman
I created this for two reasons:
screen -xRS foo
because systemd .service
files are way too hard to get right and even harder to debug. I make stupid typos or config mistakes and get it wrong. Then I get a notice 18 months later from digital ocean that NYC region 3 is being rebooted and to expect 5 seconds of downtime... and I don't remember if I remembered to go back and set up that service with systemd or not.serviceman | MPL-2.0 | Terms of Use | Privacy Policy
Copyright 2019 AJ ONeal.