launchd plist xml to run job several times a day?

I've been reading about using launchd instead of cron.


For the life of me I can't find out how to run a script at 10AM and 2PM


Can you use:

<key>StartCalendarInterval</key>

<dict>

<key>Hour</key>

<integer>10</integer>

<key>Hour</key>

<integer>14</integer>


or maybe


<key>StartCalendarInterval</key>

<dict>

<key>Hour</key>

<integer>10</integer>

<integer>14</integer>



Maybe I need 2 plists?


If I wanted to run it every X minutes, I can program that into the XML but I don't know how you could do several specified times a day... or for that matter just on Monday and Friday?


I've Googled all night and can't find an example. What is the trick... if there IS a trick?


Thanks,


Al

iMac, Mac OS X (10.7.1)

Posted on Sep 29, 2011 11:40 PM

Reply
21 replies

Sep 30, 2011 8:35 AM in response to al1776

al1776 wrote:


So where do I put the plist for a job to be run as root? in ~/library/launch... (user) or in /library/launch... (system.)?


What exactly is an "on demand" job?


How do I change when a job runs? Yes, chage the plist... but do I have to re-launch it?


ok, process broken down in detail:


a launchd plist is essentially a configuration file. it does (effectively) three things:

  • sets up a label to identify the job in launchd
  • points to a script or utility that will be run when the conditions are right
  • establishes a set of conditional triggers that outline when the script or utility should be run

There are a number of different triggers that can be used:

  • StartInterval - ever X seconds
  • StartCalendarIntervel - at particular dates and times
  • OnLoad - when the plist is loaded into launchd
  • OnMount - when a file system is mounted
  • KeepAlive - re-run the process whenever the process quits (with conditions)
  • etc.

OnDemand is deprecated - basically it's the same as KeepAlive (OnDemand/true = KeepAlive/false). don't use it.


the way the process works is that the launchd plist is loaded into launchd (at system reboot, login, or when launchctl load is run). launchd reads it as a configuration plist and creates a launchd job based on the information it finds. This job stays active until removed.


if you want to change the configuration, do this.

  1. modify and save the plist file
  2. remove the currently running job (shutdown, log out, launchctl remove label or launchctl unload plist)
  3. reload the modified plist file to create a new job (restart, log in, launchctl load plist)


if you want to test a job to see if it's working, use launchctl start label, which triggers the job to run the script or utility. then run launchctl list and look for the label name. it should look something like:


- 0 Label


the - might be a number if the script is still running (it's the process ID). the 0 means successful execution the last time the utility was triggered (a non-zero number means the script threw an error when run)


if there's no GUI then put the plist file in /Library/LaunchDaemons. that will run it as root in the background. If you find it throws errors that way, you might try it in /Library/LaunchAgents - that runs it with administrator privileges but in the login window of a user, so it can access aqua features. but this really sounds like a daemon to me, so...

Sep 30, 2011 5:22 PM in response to al1776

In Apple's system-lingo: "A daemon is a program that runs in the background as part of the overall system (that is, it is not tied to a particular user). A daemon cannot display any GUI; more specifically, it is not allowed to connect to the window server." (see Tech Note 2083) It doesn't have to be a continuously running program, just one that doesn't interact with users directly. Your script will probably work in either location, mind you, so the distinction might be academic.


All enabled plists are loaded at restart or login. Enabled plists are plists in one of the three user-accessible launchd folders (already mentioned) which are not explicitly disabled by a Disabled key set to true (it's actually a little more complicated than that - the Disabled key in the plist is 'advisory', and the system stores the real enabled list in an undisclosed location - but it usually works). You only need to use launchctl if you are manually updating a plist and don't want to log out, or sometimes in super-tricky cases where you want to programmatically load a plist (in those cases you set the plist's Disabled key to true so it doesn't load, and then script launchctl to load it by override the Disabled key with the -F or -w options. probably TMI). it is set-it-and-forget-it.


There's no simple utility for this, I think, because not that many people use launchd directly, and those few who do tend to write plists, toss them in the correct folder, and forget about them. I have a applescript I use for loading and reloading plists which I keep in the script menu:


on run

tell application "Finder" to set theItems to the selection as alias list


relaunchd(theItems)

end run


to relaunchd(theItems)

repeat with thisPlistFile in theItems

tell application "Finder" to set containerName to displayed name of container of thisPlistFile

if containerName is in {"LaunchAgents", "LaunchDaemons"} then

set thePath to quoted form of (POSIX path of thisPlistFile)

do shell script "launchctl unload " & thePath

do shell script "launchctl load " & thePath

end if

end repeat

end relaunchd


The difference between launchd and cron is that cron is (pardon me for putting it this way) a unix-geek tool: its language is highly compressed and symbolic. good for fast typing in a command-line environment, bad because a single mistyped character can become a major headache to diagnose and fix. Launchd (like many things Apple) is much more verbose and 'natural language'-like, which means a lot more typing but a generally more user-friendly experience (once you wrap your head around it). tradeoffs vs. tradeoffs.

Sep 30, 2011 8:12 AM in response to twtwtw

I'm reading "man launchctl" here:

http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/ man1/launchctl.1.html


Very confusing. So where do I put the plist for a job to be run as root? in ~/library/launch... (user) or in /library/launch... (system.)?


What exactly is an "on demand" job?


How do I change when a job runs? Yes, chage the plist... but do I have to re-launch it?


Honestly, crontab is a lot easier than the launchd stuff... and better documented since it has been around for a hundred years! But I'll figure out this new launchd eventually.


Thanks for your help.


Al

Sep 30, 2011 8:06 AM in response to al1776

That's two questions. 😝

  • do not put anything in the /System folder unless you know exactly what you're doing - that is for Apple's use. Use /Library/LaunchAgents or /Library/LaunchDaemons.
  • launchd plist must be loaded as jobs to run, and must be removed as jobs to make them stop running. there are two ways to load a plist as a job
    1. reboot the system (or logout/login for user plists)
    2. remove/reload a script using launchctl in terminal (launchctl load /path/to/plistfile.plist, launchctl unload /path/to/plistfile.plist, launchctl remove job.label)

read man launchctl

Sep 30, 2011 12:11 AM in response to al1776

Have you read the launchd plist documentation? In terminal type (copy/paste) the following line:


man 5 launchd.plist


I think the problem here is that you can run a tasks at fixed intervals so you can't do what you want with a single launchd item. But I don't think there is anything stopping you from writing two items, one to run every day at hour 10 and the other to run every day at hour 14.

Sep 30, 2011 12:06 AM in response to X423424X

I didn't see anything in there about multiple times. However, since my post I think I've found out how to do it...


<key>StartCalendarInterval</key>

<array>

<dict>

<key>Hour</key>

<integer>12</integer>

<key>Minute</key>

<integer>0</integer>

</dict>

<dict>

<key>Hour</key>

<integer>14</integer>

<key>Minute</key>

<integer>0</integer>

</dict>

</array>


I've not tried it so I don't know if it works. Will report back.

Sep 30, 2011 7:43 AM in response to al1776

Might I ask one more question?


One initializes a launchd plist via launchctl.


If I want to change the hours that it runs, say from 10 and 2 to 11 and 4, of course I have to change the plist. Do I have to re-load it with launchctl? Do I need to unload it first?


Also, my bash script MUST be run as root. Does it goe in the system (not user) Library Agents or Deamons?


(Right now I'm using cron... which works fine on Lion... but people tell me Apple may pull the plug on it in a later update and that I should switch to launchd.)


Thanks.

Sep 30, 2011 8:12 AM in response to twtwtw

sorry, to clarify:


~/Library/LaunchAgents - run job as user for a particular user

/Library/LaunchAgents - run job as user for every user

/Library/LaunchDaemons - run job as root for every user


keep in mind that LaunchDaemons need to be background only - if you need to launch a GUI app as root (a funky scenario that you probably shouldn't be doing anyway) you'll need to be creative.

Sep 30, 2011 8:20 AM in response to twtwtw

Thanks. This job must be run as root twice a day. No GUI interface. It uses rsync to go to a server and bring down some mySQL dump files and then reloads the local MySQL databases so they are in sync (at least twice a day!!) with the production database, one of which is SugarCRM.


It's just a bash script that logs into the server, grabs the files and then reloads the local data running under XAMPP. XAMPP requires that the databases be started and stopped as root. I wish there was a way around that but I've never found it. The script has been running fine under cron but I'm having a devil of a time figuring out how to schedule it with launchd. Any help is always appreciated.

Sep 30, 2011 8:27 AM in response to al1776

Interesting. There are TWO Library directories under the "system" (Macintosh device) in Finder.


/System/Library


and


/Library


They both have LaunchAgents and LaunchDeamons sub-dirs.


I didn't know that... and so what you are saying is stay the heck out of the /System directory and use the /Library instead.


Thank you.

Sep 30, 2011 4:35 PM in response to twtwtw

That was a great reply. You really spelled it out for me and others. It's amazing how little comprehensive detail there is on this utility out there... for non-Unix experts.


I don't think my script is a damon as it only has to be run a couple of times a day. I always think of a daemon as something that lurks in the background checking ports or waiting for something to happen before it springs into action.


One other question. If I re-start or cold-start are you saying I'll have to do a launchctl load command? Is there a way to tell it to be "active" when the computer starts (this is a one-user (me!) machine. I cold-boot it once a week to clean out the whatever stuff is there to be cleaned!) The nice thing about cron is that it is set-it-and-forget-it... no worry about restarts etc... the OS starts the crontab stuff.


I'm surprised that Apple (or someone) didn't create a nice little utility for people to schedule jobs with launchd... similar to what Cronix is for cron (Cronix does let you set the root cron, but lets you set the user cron just fine.) I see there is Legon or something like that but I don't think it launches the system... just lets you create a plist XML file... which is not that difficult to do with a text editor and a "borrowed" plist.


Thanks,


Al

Oct 2, 2011 3:14 PM in response to al1776

Well, thanks to the help I received here I got my script running via the launchd facility.


A few observations for those who want to try this.


1. The "fire time" is not as precise as cron... my 2:00 PM seems to kick off at 2:01 or 2:02. Cron is always dead-ontime.


2. When you pop your plist in /Library/LaunchDaemons I don't think you can just save it out from Textwrangler (and enter password when prompted.) I found I had to do it in root... sudo cp my-plist /Library/........


3. Editing cron (sudo crontab e) is a lot easier and faster than having to unload and then load a plist file.


4. If you have a syntax error in the plist, you don't get any diagnostics (or meaningful ones) from the load command. You get a "nothing to load" message. Yeah that's helpful!


5. The XML parms for scheduling a job multiple times is easier to understand than the cryptic crontab entries, but again you can have syntax/coding errors if you leave out a closing </array> tag or a mis-matched <dict>. The nesting of XML can be hard on the eyes to figure out.


6. The "launchctl list" command does not show my job as being loaded. I think it only shows jobs that are currently running. I've not figured it out.


I can see where launchd is more "featured" than cron, but not enough for the average user, in my opinion. I fail to see why Apple has deprecated cron... and has hinted that it may not support it in future releases. One of the great features of OS X is that Unix people can love it too! I hope Apple keeps the tried-and-true Unix utilities in OS X... which makes it the "better Linux."


Thanks for your help.


Al

Oct 3, 2011 9:15 AM in response to al1776

lol - well, it sounds a little 'miffed', and you've forgotten or glossed over a few useful points (e.g., the fact that they don't have to use launchctl to load the plist except when they are editing it). If you'd like I'll do a quick collab on it for form and content, and toss in some launchd templates I have lying around as well. let me know. :-)

Oct 3, 2011 10:05 AM in response to twtwtw

I'm not really miffed... it's just that Apple made this utility harder than it had to be... and didn't provide a simple (i.e. like Cronnix) front end to it for us.) I basically wanted to inject a bit of humor into the piece. I also hate XML... but that's just me!


Sure, by all means feel free to edit it. You can grab the source code from your browser. It's just simple HTML that I threw together in a few minutes.


I don't think you can email me privately from this board.


Use the email contact form at www.ancins.com to write me with YOUR email and I'll reply with one of mine... you can then send the edited file back to me and I'll upload it.


I'll BE HAPPY to give you full attribution along with your web site if you code it in there.


Regards,


Al

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

launchd plist xml to run job several times a day?

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.