Initial support for run-one
Include support for executing only one instance of a command to prevent executing the same command multiple times by mistake Inspiring run-one tool https://launchpad.net/run-one
I won't be able to review this before the weekend. So set your expectations of review response accordingly.
Furthermore, I'm not quite convinced such feature belongs into runitor. I can see how it can be useful, especially for tasks which sometimes take longer to run than their intended run interval. ...but how this integrates seamlessly with a Healthchecks, that I'm not sure yet. Need to think about it.
Ok, I have no problems
The main idea is to prevent 2 or more processes from overlapping, especially in long processes used especially in cron. For example, if you launch an initial backup that takes longer, do not run it again in the next cron time interval to avoid corrupting the backup or generating false positives.
Thnaks.
I'm not very fond of adding a non-straightforward feature like this.
opinionated
Looks like the implementation hashes the passed command. This is one way of achieving single instance execution. I don't think it is a once-size-fits-all one. Take the example of a backup process that has a tendency to long sometimes. If I'm passing runitor a non-deterministic command line, say, a datestamp: runitor -slug slothbackup -- tarsnap -f backup-20241213_01, then the next time it gets called with a different datestamp, this mechanism will think these distinct command and allow execution. that's a quite the gotcha.
I don't think there's much room for such opinionated implementations for such diverse use cases.
fragile
In its current form, this implementation is fragile. If unitor crashes, looks like the lock file will be left around. I guess that could be fine if we could check the process that prompted creation of the lock file was still running. Maybe... If you recorded the PID of it.
a simpler and older concept already exists
Taking a step back, and thinking if there's something similar to this in the Unix world, pid files come to mind. The choice of the path of the pidfile can be entirely left to the user to begin with. In a later commit a per-OS pidfile parent directory auto prepending can be added. The upshot of this is 1) user familiarity with the concept, 2) flexibility given to the user: if they choose the same pidfile basename, regardless of their command line argument structure, they get to decide what gets groups, what doesn't. 3) because the pidfile will include the PID, runitor can also check if the pidfile's originator process is still alive; and commandeer the file if it isn't.
windows and unixen other than linux
I would love if you also consider how this would work under Windows. The implementation doesn't need to be identical. Go's build constraints //go:build <os-plat-expr> trivially allows us to plug the swap in the correct implementation at compile time. You are already using os.TempDir() which Go takes care of making it portable across different operating systems by following the conventional environment variables or defaulting to a specific path. So you're almost there.
is there a composable alternative?
I don't know if an easy command line tool exists that implements pidfile functionality. Such a tool would be almost similar to runitor in command wrapping functionality, but would perfectly work, The Unix Way, to compose richer functionality.
A feature request I turned down at least twice in the past was the addition of maximum execution time limits. That's the sole purpose of GNU coreutils timeout on Linux, (and macOS), timeout(1) on OpenBSD and FreeBSD, but sadly nothing straightforward and standard on Windows.
I'd like to thank you for your contribution. I'm glad to see not only someone found runitor useful, but they cared enough about it to contribute. Hopefully you'd be interested in incorporating the feedback above. No worries if you don't want to take another stab at this right away though. I may end up finding another weekend to introduce this, or someone else reading these lines could.