Launchd 作业运行但随后立即退出

Launchd 作业运行但随后立即退出

我希望在我的 Mac(OS 10.9)启动时自动在后台加载并运行 CCL 中的 Lisp 程序。我有一个已保存到 /Library/LaunchDaemons 的 launchd 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>Label</key>
    <string>com.icecreamcomputer</string>
    <key>ProgramArguments</key>
    <array>
            <string>sudo</string>
            <string>/Applications/ccl/./dx86cl</string>
            <string>-l</string>
            <string>/Users/frank/Documents/Lisp/ice-cream-computer/ice-cream-computer.lisp</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

当我打电话时

launchctl load /Library/LaunchDaemons/com.icecreamcomputer.plist

从终端,我可以在 top 中看到 dx86cl 运行了几秒钟,然后消失了。之后 launchd 会将该作业列为已退出。但是,如果我调用

sudo /Applications/ccl/./dx86cl -l /Users/frank/Documents/Lisp/ice-cream-computer/ice-cream-computer.lisp

从终端,我的程序启动并保持运行,没有问题。是什么原因导致我的 launchd 作业在启动后立即退出?

以下是 /var/log/system.log 中的条目:

Apr 15 10:01:55 frynseytv.icecreamcomputer.com sudo[34963]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/Applications/ccl/./dx86cl -l /Users/frank/Documents/Lisp/ice-cream-computer/ice-cream-computer.lisp
Apr 15 10:01:58 frynseytv com.apple.launchd[1] (com.icecreamcomputer): Throttling respawn: Will start in 8 seconds
Apr 15 10:02:00 frynseytv com.apple.launchd.peruser.501[306] (com.icecreamcomputer[34965]): open("/var/log/icecreamcomputer.log", ...): 13: Permission denied
Apr 15 10:02:02 frynseytv com.apple.launchd.peruser.501[306] (com.icecreamcomputer): Throttling respawn: Will start in 8 seconds

显然它没有权限打开名为“/var/log/icecreamcomputer.log”的日志,而且确实不存在这样的文件或目录。虽然这看起来很奇怪,因为 root/wheel 拥有 /var/log/icecreamcomputer.log,并且 root 运行 launchd,其他进程 launchd 启动,不是吗?以下是 /var/log/icecreamcomputer.log 的摘录。它显示了 icecreamcomputer.lisp 加载时通常会打印到 stdout 的内容。它缺少的是记录的 http 服务器活动,例如接收和满足请求。

Welcome to Clozure Common Lisp Version 1.9-r15759  (DarwinX8664)!
? 
==== quicklisp quickstart loaded ====

To continue with installation, evaluate: (quicklisp-quickstart:install)

For installation options, evaluate: (quicklisp-quickstart:help)

To load "hunchentoot":
Load 1 ASDF system:
hunchentoot
; Loading "hunchentoot"

实际上,当我 tail -f /var/log/icecreamcomputer.log 时,它继续限制重生并说即使我调用 launchctl unload /Library/LaunchDaemons/com.icecreamcomputer.plist 也无法写入日志。它只在服务器重启后停止循环。这是怎么回事?

重启后,我尝试再次加载守护进程。没有错误消息,但 launchctl list 显示进程已退出,并且在加载守护进程的 plist 时,跟踪 icecreamcomputer.log 显示没有活动。

答案1

听起来你的 LISP 编程违反了 launchd 的守护进程要求:

“您不能将进程设为守护进程。这包括调用守护进程函数、调用 fork 后执行 exec,或调用 fork 后退出。如果这样做,launchd 会认为您的进程已终止。根据您的属性列表键设置,launchd 会继续尝试重新启动您的进程,直到它放弃(出现“重生太快”错误消息),或者如果它确实终止,将无法重新启动它。”

来源:https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html

为了更好地理解 launchd — 尤其是 plist 语法 — 我建议编写一个带有无限循环的 hello world 脚本,使用 logger(1) 命令每隔约 5 秒写入 sylog。让脚本在前台和后台运行以查看差异。此外,使用 plutil(1) 仔细检查容易被忽略的语法错误。

Apple 在 /System/Library/LaunchDaemons 中的 launchd 作业也是一个很好的参考。请注意,特别是 apache 作业,它使用:

/usr/sbin/httpd -D 字符串>FOREGROUND

解决 launchd 的守护进程要求。

祝你好运!

相关内容