There are several apps I run in the background on my laptop that occasionally crash, e.g. Google Drive for Desktop. After several crashes that I didn’t notice for a few days each, I’d had enough and decided I needed tooling to automatically restart certain apps. I searched for existing tools but only found some blog posts about the problem, so I wrote my own. The implementation is relatively simple on MacOS X: launchd exists to run daemons and apps and restart them as necessary, so mostly I just needed to generate configuration files - but that didn’t allow updating apps, so I needed a wrapper around the apps too.
There are three parts to the implementation:
- restart-app-automatically
- This program generates and manages
plist files that configure
launchd
to start the desired app (via the wrapper below) and restart it when it exits. It useslaunchctl
to load the configs, restart apps, remove configs, and so on. - restart-app-automatically-wrapper
- When upgrading an app the typical process is 1) stop the app, 2) overwrite
files, 3) start the app. If step 3 happens before or during step 2 the upgrade
may fail, so I can’t just have
launchd
restart the app directly because it will do so immediately after the app exits.launchd
does have aThrottleInterval
option that looks like it would solve the problem, but that just enforces a minimum time period between job starts, so if a job has been running for longer thanThrottleInterval
seconds (true in the common case) it will start again immediately. The wrapper sleeps for 60 seconds after the app exits to give upgrades a chance, and when the wrapper is executed again bylaunchd
it kills any app processes that were left hanging around when the previous run finished then runs the app. - Per-app wrapper programs
- They aren’t strictly necessary, but for ease of use and consistency I have a small wrapper program for each app, e.g. for Google Drive I have restart-google-drive-automatically.
Mac OS Mojave introduced a small problem: restart-app-automatically-wrapper
needs extra permissions, but thankfully a dialog appears making it easy to grant
the permissions:
It’s unclear what happens if you press Deny
though - will you ever get a
chance to approve it again?