Using `at` for one time jobs with really high granularity

tuaris

Active Member

Reaction score: 4
Messages: 123

I'm putting together a service script using /usr/libexec/atrun where it would monitor a directory (or run atq) for incoming 'job' files, move the file to a 'running' directory, execute the job, then finally remove the file. The idea here is that instead of polling for jobs (how it's currently done with the cron approach) this would be instantaneous.

The monitoring script, forking the processes, and keeping track of the states is functional. I already have it in use for another solution. The part I'm stuck on is how to point at and atrun to a custom directory other than /var/at/jobs so that it does not interfier with the crontab version of it.
 

olli@

Well-Known Member
Developer

Reaction score: 276
Messages: 315

I'm afraid the standard at and atrun programs don't provide a way to specify the directory for job files.

However, in the case described above I would not use at/atrun, but use a simple loop to poll the directory. Assuming you use /bin/sh, it would look something like this:
Code:
#!/bin/sh
JOB_DIR="/your/job/directory"
LAST_MTIME=0
while :; do
        NEW_MTIME=$(stat -f '%Fm' "$JOB_DIR")
        if [ $NEW_MTIME != $LAST_MTIME ]; then
                # ... look for new jobs and handle them ...
                LAST_MTIME=$NEW_MTIME
        else
                sleep 60    # ... or whatever granularity you want
        fi
done
It works by looking at the so-called mtime (modification time) of the directory. This mtime is updated each time the directory contents change (e.g. a file is added or removed). Checking the mtime is more efficient than retrieving a directory listing, and efficiency is important if you poll it often.

A much better way would be to not use polling at all, but get notified whenever the directory changes. The two advantages are: (a) you don't have to check the directory regularly, and (b) your script will react instantaneously, i.e. within fractions of a second. This can be done with FreeBSD's kqueue(2) feature. To use it from a shell script, you can use the wait_on package (Port sysutils/wait_on). This is quite easy to use, please see its manual page for detailed explanation and examples.
 

SirDice

Administrator
Staff member
Administrator
Moderator

Reaction score: 7,292
Messages: 29,742

The idea here is that instead of polling for jobs (how it's currently done with the cron approach) this would be instantaneous.
Why don't you simply run the script when you detect the change? What's the point of detecting a change only to schedule a cronjob at a moments notice?
 
OP
OP
tuaris

tuaris

Active Member

Reaction score: 4
Messages: 123

Why don't you simply run the script when you detect the change? What's the point of detecting a change only to schedule a cronjob at a moments notice?
I was considering that as an option, (bypassing atrun completely). The main reason I want to use atrun is because it already implements the permissions mechanism for allowing who can run what commands. I want to allow some root level tasks to be executed by specific non-root users (ie. restarting a service).

A much better way would be to not use polling at all, but get notified whenever the directory changes. The two advantages are: (a) you don't have to check the directory regularly, and (b) your script will react instantaneously, i.e. within fractions of a second. This can be done with FreeBSD's kqueue(2) feature. To use it from a shell script, you can use the wait_on package (Port sysutils/wait_on). This is quite easy to use, please see its manual page for detailed explanation and examples.
Thanks for that tip and the suggestion to use mtime.
 
OP
OP
tuaris

tuaris

Active Member

Reaction score: 4
Messages: 123

I just realized that I can probably solve the permissions issue using the sudo command.
 
Top