Launch Daemon for NodeJS App Won’t start on reboot

daemonslaunchd

I've created the below launch daemon to run a nodejs program on startup (tiddlywiki in this case):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Debug</key>
        <true/>
        <key>StandardOutPath</key>
        <string>/tmp/tiddlywiki.stdout</string>
        <key>StandardErrorPath</key>
        <string>/tmp/tiddlywiki.stderr</string>
        <key>Label</key>
        <string>com.activescott.tiddlywiki</string>
        <key>OnDemand</key>
        <false/>
        <key>RunAtLoad</key>
        <true/>
        <key>KeepAlive</key>
        <true/>
        <key>inetdCompatibility</key>
        <dict>
            <key>Wait</key>
            <true/>
        </dict>
        <key>EnvironmentVariables</key>
        <dict>
            <key>PATH</key>
            <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
        </dict>
        <key>ProgramArguments</key>
        <array>
            <string>/Volumes/minidata/Dropbox/tiddlywiki/node_modules/.bin/tiddlywiki</string>
            <string>/Volumes/minidata/Dropbox/tiddlywiki/wiki</string>
            <string>--listen</string>
            <string>credentials=creds.csv</string>
            <string>writers=scott</string>
            <string>readers=scott</string>
            <string>port=443</string>
            <string>host=0.0.0.0</string>
            <string>tls-key=key.pem</string>
            <string>tls-cert=server.crt</string>
        </array>
    </dict>
</plist>

The file is named com.activescott.tiddlywiki.plist and it is in the /Library/LaunchDaemons/ folder.

If I load it with the command:

sudo launchctl load -Fw /Library/LaunchDaemons/com.activescott.tiddlywiki.plist

I start it with the below command it and wills tart and work fine – it just doesn't restart automatically when the comp reboots:

sudo launchctl start com.activescott.tiddlywiki

Note, it does take about ~20s to fully start (e.g. respond on a port and write to stdout).

I'm on Mac OS X, 10.13.6 w/ BuildVersion 17G13035

Update:

After a reboot I noticed that the output of sudo launchctl list com.activescott.tiddlywiki shows LastExitStatus as 19968. This value will show 0 if I start it with launchctl. Below is the full output:

{
        "StandardOutPath" = "/tmp/tiddlywiki.stdout";
        "LimitLoadToSessionType" = "System";
        "StandardErrorPath" = "/tmp/tiddlywiki.stderr";
        "Label" = "com.activescott.tiddlywiki";
        "TimeOut" = 30;
        "OnDemand" = true;
        "LastExitStatus" = 19968;
        "Program" = "/Volumes/minidata/Dropbox/tiddlywiki/node_modules/.bin/tiddlywiki";
        "ProgramArguments" = (
                "/Volumes/minidata/Dropbox/tiddlywiki/node_modules/.bin/tiddlywiki";
                "/Volumes/minidata/Dropbox/tiddlywiki/wiki";
                "--listen";
                "credentials=creds.csv";
                "writers=scott";
                "readers=scott";
                "port=443";
                "host=0.0.0.0";
                "tls-key=key.pem";
                "tls-cert=server.crt";
        );
};

Best Answer

Presuming your application can be run within the Terminal, making an AppleScript program (using Script Editor) containing the commands that you would run in the terminal and then exporting that program as a Run-Only Application, placing it in your /Applications/ directory can create your program launcher.

There is a helpful answer on using do shell script in AppleScript here.

AppleScript Example: Running hdiutil to mount a sparseimage bundle as a Time Machine backup drive

do shell script "hdiutil attach /Volumes/NewVolumeD/TimeMachine.sparsebundle"

Then, navigating to System Preferences > Users & Groups > (your account) > Login Items, unlocking the settings menu and then using the + button on the bottom left to select your launcher application from Applications. That launcher will now run on login, check mark on Hide so that it doesn't throw unwanted messages.

Alternatively, you could make a zsh or bash script and tell AppleScript execute the shell script (given its absolute path) instead of specifying each command in AppleScript itself.

EDIT: Instead of using Login Items, you can place the Application Bundle in /Library/StartupItems (though it is deprecated) if you want it to launch on startup instead of login.