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:

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 uses launchctl to load the configs, restart apps, remove configs, and so on.
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 a ThrottleInterval 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 than ThrottleInterval 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 by launchd 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:

Extra permissionsdialog

It’s unclear what happens if you press Deny though - will you ever get a chance to approve it again?