using launchd instead of startupitems

started at 11 Nov 2006 by Michael
  • Michael
    11 Nov 2006
    I prefer launchd to startupItems. There's not currently much advantage to one or the other the way I use launchd, except that if my database crashes launchd will restart it.

    Richard and I discussed this and thought it might be useful to bring to the forum, so here it is.

    I start MySQL with the following file as /Library/LaunchDaemons/org.mysql.MySQL5.plist:

     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
     "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     <plist version="1.0">
     <dict>
        <key>GroupName</key>
        <string>admin</string>
        <key>Label</key>
        <string>MySQL5</string>
        <key>OnDemand</key>
        <false/>
        <key>Program</key>
        <string>/usr/local/mysql/bin/mysqld_safe</string>
        <key>RunAtLoad</key>
        <true/>
        <key>ServiceDescription</key>
        <string>Launches the MySQL database server</string>
        <key>UserName</key>
        <string>root</string>
     </dict>
     </plist>


    --
    For Apache2, I have to use a shell script to get around the way launchd responds to apps that quit in less than 10 seconds.
    The first file is launchd_apache.sh:

     #!/bin/sh
     /Library/Apache2/bin/apachectl graceful
     
     sleeptime=40
     
     httpdArray=(`ps -U www | grep httpd | awk '{print $1}'`);
     let httpdCount=${#httpdArray[*]};
     
     while (($httpdCount > 0))
     do
        sleep $sleeptime;
        hpptdArray=(`ps -U www | grep httpd | awk '{print $1}'`);
        let httpdCount=${#httpdArray[*]};
     done
     
     echo "Apache Stopped, restarting..."



    The second is the LaunchDaemon that uses it:

     <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
     "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
     <plist version="1.0">
     <dict>
        <key>GroupName</key>
        <string>admin</string>
        <key>Label</key>
        <string>Apache2</string>
        <key>OnDemand</key>
        <false/>
        <key>Program</key>
        <string>/Library/Apache2/bin/launchd_apache.sh</string>
        <key>ProgramArguments</key>
        <array>
           <string>/Library/Apache2/bin</string>
           <string>graceful</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>ServiceDescription</key>
        <string>Launches the Apache2 httpd web server</string>
        <key>UserName</key>
        <string>root</string>
     </dict>
     </plist>



    Edit: fixed typo. Thanks, dtgriscom!
  • Richard
    15 Nov 2006
    Thanks Michael for posting this explanation. I will add my opinion here as well as I did via email to Michael.

    I like the solution Michael has presented and it does have it advantages, but it also has some drawbacks.

    Most of the software, like MySQL and Apache, came with startup scripts and it was the way postfix was normally started on OS X. I want to support the most simple and standard way that most people/systems use so I copied that and continued on that note. With the startupparameters.plist file you can define dependancies like what has to be running. For instance DSPAM need MyQL running.

    Michael provides a different solution for the same task and that's great. It's all about choice for me and therefore urged MIchael to post his solution here for everybody's benefit.
  • dtgriscom
    05 Dec 2006
    I've used this to get Apache starting on boot, which was very helpful. I'd like to share what I learned in the process:

    1: There's a typo in the launchd code. The following line

    <string>/Library/Apache2/bin/launchd_apache.shl</string>



    should be

    <string>/Library/Apache2/bin/launchd_apache.sh</string>



    2: The launchd_apache.sh assumes that the Apache user is www; on my system it's root. To change this, change both occurrences of

    httpdArray=(`ps -U www | grep httpd | awk '{print $1}'`);



    to

    httpdArray=(`ps -U root | grep httpd | awk '{print $1}'`);



    3: A more complete description of launchd_apache.sh would be helpful to random Googlers (such as myself). launchd launches processes, and expects those processes to continue forever; it treats a process that ends as an error, and relaunches it. apachectl normally starts httpd and then exits, which would confuse launchd. So, here launchd runs launchd_apache.sh. launchd_apache.sh runs apachectl, then sits there watching the process list for the resulting httpd instances (matched by user and "httpd"). As long as there are such processes, launchd_apache.sh continues waiting; once they are all gone, launchd_apache.sh exits, and launchd restarts launchd_apache.sh.

    4: If you elsewhere run "apachectl graceful" to restart httpd, then it's possible launchd_apache.sh will see that moment when there are no httpd instances, exit, and cause launchd to run its own "apachectl graceful". That means the clean way to do this would be to run "apachectl stop" and wait the 40 seconds for launchd to restart things. In reality, this is very unlikely, and isn't a big deal if it does happen, so "apachectl graceful" is still probably the way to go (and avoids your waiting for launchd to kick in).

    Thanks for the useful post,
    Dan

Reply

You must log in to post.