launchd vs periodic

When launchd debuted with Tiger, Apple moved the execution of the periodic jobs, previously scheduled by cron, to launchd. I had been using anacron, as I wanted these jobs to run even if the machine had been off or asleep at the magic hour. Under Tiger, I kept using anacron, as there were lots of reports of launchd not reliably running repeating jobs.

In Leopard, these issues seemed to have been solved, and in my testing, launchd would reliably run the periodic jobs and even run them after wake up if the machine had been asleep during the scheduled time.

But I (and Apple) missed something: launchd still won’t run missed tasks if the machine is off when the job was scheduled.

I slowly became aware of this as I noticed machines not doing things I had scripted them to do as part of the daily periodic tasks. I finally realized that machine that were off overnight never ran the periodic tasks. This problem was worsened when I implemented some power management scripts that shut down machines at night if no-one was logged in, powering them back on in the AM.

So I’ve written a partial replacement for anacron that works with the periodic daily, weekly and monthly tasks. It’s meant to be run at startup, and checks the modification dates on /var/log/daily.out, /var/log/weekly.out, and /var/log/monthly.out, running the appropriate periodic job if it’s overdue.

#!/usr/bin/perl -w

# psuedo_anacron
# a script to run overdue periodic jobs
# at startup, working around a missing
# feature of launchd
#
# Greg Neagle, http://managingosx.wordpress.com

use strict;

my $logDir = "/var/log";
my $now = time;

my %periodicJobs = (
    daily => 1,
    weekly => 7,
    monthly => 30
);

while(my($job,$frequency) = each(%periodicJobs)) {
    my $needToRunJob = 1;
    if (-f ("$logDir/$job.out")) {
        my $fileModTime = (stat("$logDir/$job.out"))[9];
        my $ageInDays = ($now-$fileModTime)/(60*60*24);
        if ($ageInDays < $frequency) {
            $needToRunJob = 0;
        }
    }
    if ($needToRunJob) {
        system "/usr/bin/logger -t psuedo_anacron \"Running periodic $job because it last ran more than $frequency days ago.\"";
        system "/usr/sbin/periodic $job";
    }
}
Explore posts in the same categories: General, OS X

Tags: , ,

Both comments and pings are currently closed.

8 Comments on “launchd vs periodic”

  1. jan Says:

    Nice one!
    That’s a pretty neat workaround.

  2. bethany Says:

    hi greg! did you report this as a bug to apple? do you guys have official apple support?

  3. GregN Says:

    If you read the man page for launchd.plist (specifically, the section on the StartInterval and StartCalendarInterval keys), it makes no claim that events missed while the machine is off will be run, so I’m fairly confident that Apple would close it as “behaves as designed”.

    I’ll probably file it anyway…

  4. neuwalker Says:

    Hi Greg,

    I tried your script and called it via launchd at every startup (which often happens twice a day). Every single periodic script ran every time, until I found out, that my periodic scripts log to
    /var/log/daily.log
    /var/log/weekly.log
    /var/log/monthly.log
    but I have daily.out ect. too.

    I changed your script and now it looks better. But what are the differences between both files and how can I change the log files?

  5. GregN Says:

    Have you modified /etc/defaults/periodic.conf, /etc/periodic.conf, or /etc/periodic.conf.local ?

    By default, the periodic logs are in /var/log/: daily.out, weekly.out, and monthly.out, but many things, including the logfile names can be modified by editing the .conf files list above. In fact, since /usr/sbin/periodic itself is just a shell script, it’s pretty trivial to modify its behavior by modifying the shell script itself…

    -Greg

  6. neuwalker Says:

    Thank you Greg, that’s it. Someone – not sure if it was me – changed the /etc/periodic.conf to write output to daily.log on March 23rd, which was the date of the first output in that file.

    So now I should change your script to look in the file you listed up to find the right log-file to observe.

  7. airdrummer Says:

    i’ve also used anacron since b4 10.4…perhaps that’s why the period tasks are being run 2x?


  8. Hey,

    Have you done anything with user-level cron jobs, or user-level LaunchAgents? For network NIS users we find that cron jobs don’t run after reboot, presumably because cron did it’s initial checks before ypbind ran. And since our users are on NFS-mounted homes, I can’t imagine that user-level launch agents would work at all after a reboot, although I admit I haven’t tried it yet. Not that I would find that a suitable replacement for users anyway…

    I’m trying to come up with a fix (like a system launch agent that waits for NIS, and then nudges cron), but was wondering if you’d already dealt with this.

    tom


Comments are closed.


Follow

Get every new post delivered to your Inbox.

Join 191 other followers

%d bloggers like this: