macOS 提供了多种进程自动化和服务管理方法,每种方法适用于不同的场景。从原生的 launchd 系统到特定语言的进程管理器(如 PM2),了解这些工具对于在 macOS 上运行后台服务、定时任务和生产应用程序至关重要。
引言
macOS 上的进程自动化不仅仅是编写脚本——它还涉及保持服务运行、调度任务以及管理独立于用户会话运行的应用程序。无论您是运行 Node.js API 的开发者、管理系统服务的系统管理员,还是调度 Python 脚本的数据科学家,macOS 都能为您提供量身定制的工具。
本指南涵盖 macOS 上主要的进程自动化方法:
• launchd - macOS 原生初始化系统
• brew services - 简单的 Homebrew 服务管理
• PM2 - Node.js 生产级进程管理器
• Supervisord/Circus - Python 进程控制
• Overmind - 使用 Procfiles 的开发环境
• cron - 传统 Unix 调度器
快速对比表
工具 | 类型 | 使用场景 | 复杂度 |
------ | ------ | ---------- | -------- |
**launchd** | 原生系统 | 生产服务、定时任务 | 高 |
**brew services** | 包装器 | Homebrew 服务 | 低 |
**PM2** | Node.js | Node.js 生产环境 | 中 |
**Forever** | Node.js | 简单 Node.js | 低 |
**Supervisord** | Python | Python/任意语言 | 中 |
**Circus** | Python | 现代 Python | 中 |
**Overmind** | Procfile | 开发环境 | 低 |
**cron** | Unix 调度器 | 传统任务 | 低 |
原生 macOS:launchd
什么是 launchd
launchd 是 macOS 的初始化系统和服务管理器,等效于 Linux 上的 systemd。它于 Mac OS X 10.4(Tiger)中引入,负责管理守护进程、代理和定时任务。macOS 上的每个进程(除内核外)最终都是 launchd 的子进程。
核心组件:
• launchd - 系统服务管理器
• launchctl - 用于管理服务的命令行接口
• LaunchAgents - 用户级服务(用户登录时运行)
• LaunchDaemons - 系统级服务(启动时运行,以 root 身份)
launchctl 命令参考
# 列出所有已加载的服务
launchctl list
# 加载服务
launchctl load ~/Library/LaunchAgents/com.example.service.plist
# 卸载服务
launchctl unload ~/Library/LaunchAgents/com.example.service.plist
# 启动服务
launchctl start com.example.service
# 停止服务
launchctl stop com.example.service
# 查看服务日志
log stream --predicate 'process == "your-process-name"' --level debugLaunchAgents 与 LaunchDaemons 的区别
LaunchAgents 和 LaunchDaemons 之间的区别是根本性的:
方面 | LaunchAgents | LaunchDaemons |
------ | -------------- | --------------- |
**运行时机** | 用户登录时 | 系统启动时 |
**运行身份** | 登录用户 | root/系统 |
**权限** | 用户级 | 系统级 |
**GUI 访问** | 是 | 否 |
**位置** | `~/Library/LaunchAgents/` 或 `/Library/LaunchAgents/` | `/Library/LaunchDaemons/` |
LaunchAgents 适用于需要 GUI 访问的用户特定任务:
• 菜单栏应用程序
• 用户自动化脚本
• 每个用户的后台服务
LaunchDaemons 适用于不依赖用户运行的服务:
• 数据库服务器
• Web 服务器
• 系统监控工具
创建 plist 文件
服务在 XML 属性列表(plist)文件中定义:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.myapp</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/Users/user/myapp/app.js</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>/Users/user/myapp</string>
<key>StandardOutPath</key>
<string>/Users/user/myapp/logs/stdout.log</string>
<key>StandardErrorPath</key>
<string>/Users/user/myapp/logs/stderr.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>NODE_ENV</key>
<string>production</string>
</dict>
</dict>
</plist>关键的 plist 键:
• Label - 唯一的服务标识符(必需)
• ProgramArguments - 要执行的命令和参数
• RunAtLoad - 加载后立即启动
• KeepAlive - 进程终止时重启
• WorkingDirectory - 设置工作目录
• StandardOutPath / StandardErrorPath - 日志文件位置
• EnvironmentVariables - 进程的环境变量
• StartInterval - 按指定间隔运行(用于定时任务)
• CalendarInterval - 在特定时间运行(cron 的替代方案)
使用 launchd 执行定时任务
在定时任务方面,launchd 很大程度上已取代 cron。使用日历间隔而非 cron 语法:
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>这将在每天凌晨 2:00 运行任务。更多示例:
<!-- 每小时 -->
<key>StartInterval</key>
<integer>3600</integer>
<!-- 每周一上午 9 点 -->
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<!-- 每月第一天 -->
<key>StartCalendarInterval</key>
<dict>
<key>Day</key>
<integer>1</integer>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>调试 launchd 服务
当服务无法启动时:
1. 检查语法:
plutil -lint ~/Library/LaunchAgents/com.example.service.plist1. 查看系统日志:
log show --predicate 'process == "launchd"' --last 1h
log stream --predicate 'eventMessage contains "com.example"'1. 检查服务状态:
launchctl list | grep com.example1. 手动执行测试:
# 直接运行命令以查看错误
/usr/local/bin/node /Users/user/myapp/app.js参考来源: Understanding macOS LaunchAgents and Login Items, What are launchd agents and daemons on macOS?
调度:launchd 与 cron
cron 的弃用状态
Apple 已弃用 cron,转而支持 launchd,但为保持向后兼容,cron 仍受支持。在 macOS Sequoia 中,Apple 还在系统设置中添加了传统 cron 支持的选项。
何时使用 launchd 调度
launchd 相比 cron 提供了以下优势:
• 更好的集成 - 原生 macOS 服务管理
• 更多触发器 - 文件监视、系统事件,而不仅仅是时间
• 睡眠处理 - 智能处理睡眠/唤醒周期
• 安全上下文 - 使用适当的 macOS 权限运行
• 日志记录 - 集成统一日志记录
将 crontab 迁移到 launchd
Crontab 条目:
0 2 * * * /Users/user/scripts/backup.sh等效的 launchd plist:
<key>Label</key>
<string>com.user.backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/user/scripts/backup.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>2</integer>
<key>Minute</key>
<integer>0</integer>
</dict>cron 仍有意义的情况
对于您已经熟悉 cron 语法的简单基于时间的任务:
# 编辑 crontab
crontab -e
# 列出 crontab
crontab -l
# 删除 crontab
crontab -r参考来源: Scheduled jobs with launchd rather than cron, Use launchd instead of crontab on your Mac
Homebrew 服务
安装
首先,如果您尚未安装 Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"然后验证安装:
brew --version什么是 brew services
brew services 是一个 Homebrew 扩展,用于简化后台服务管理。它包装了 launchd,为通过 Homebrew 安装的服务提供熟悉的接口。
# 列出所有服务
brew services list
# 启动服务
brew services start postgresql
# 停止服务
brew services stop redis
# 重启服务
brew services restart nginx
# 在前台运行服务(用于调试)
brew services run postgresqlbrew services 如何使用 launchd
brew services 自动创建 launchd plist 文件:
• 用户服务 → ~/Library/LaunchAgents/
• 系统服务 → /Library/LaunchDaemons/
例如,brew services start postgresql 会在 ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist 创建一个 plist。
常见使用场景
数据库:
brew install postgresql
brew services start postgresql
brew install mysql
brew services start mysql
brew install redis
brew services start redisWeb 服务器:
brew install nginx
brew services start nginx开发环境栈:
# 启动多个服务
brew services start postgresql
brew services start redis
brew services start memcachedGUI 工具
对于喜欢图形界面的用户:
• [BrewServicesManager](https://github.com/validatedev/BrewServicesManager) - 用于管理 Homebrew 服务的菜单栏应用程序
• [brew-services-manage](https://github.com/persiliao/brew-services-manage) - 具有日志访问功能的服务管理
参考来源: Homebrew Services: How to Use, How It Works, Managing background processes in Ventura
Node.js 进程管理器
PM2
PM2 是 Node.js 生产环境进程管理的事实标准。它提供集群、监控和自动重启功能。
安装:
npm install pm2 -g基本命令:
# 启动应用程序
pm2 start app.js
# 带名称启动
pm2 start app.js --name "api"
# 启动多个实例(集群模式)
pm2 start app.js -i max
# 列出所有进程
pm2 list
# 查看日志
pm2 logs
# 监控仪表板
pm2 monit
# 停止进程
pm2 stop api
# 重启进程
pm2 restart api
# 删除进程
pm2 delete api在 macOS 上启动 PM2(launchd 集成)
要使 PM2 在启动时自动运行:
# 生成并保存启动脚本
pm2 startup darwin
# 保存当前进程列表
pm2 save
# 现在启动您的应用
pm2 start app.js
pm2 savepm2 startup darwin 命令会生成一个在系统启动时加载 PM2 的 launchd plist,而 pm2 save 会保存当前进程列表,以便 PM2 可以在重启后恢复您的应用程序。
参考来源: PM2 Documentation, How to use pm2 startup on macOS
Forever
对于更简单的使用场景,Forever 提供基本的保活功能:
npm install forever -g
# 启动脚本
forever start app.js
# 列出运行的脚本
forever list
# 停止脚本
forever stop app.js最适合: 开发环境、简单脚本、不需要 PM2 功能时。
参考来源: Running Node.js scripts continuously using forever
其他 Node.js 选项
• nodemon - 文件更改时自动重启(仅限开发)
``bash npm install -g nodemon nodemon app.js ``
• concurrently - 同时运行多个 npm 脚本
``bash npm install -g concurrently concurrently "npm run watch" "npm run serve" ``
• nohup - 用于快速后台任务的内置 Unix 命令
Python 进程管理器
Supervisord
Supervisord 是一个成熟的 Unix 类系统进程控制系统,广泛用于 Python 环境。
安装:
brew install supervisord
# 或通过 pip:
pip install supervisor配置(`/etc/supervisord.conf` 或 `~/.supervisor/supervisord.conf`):
[supervisord]
nodaemon=false
logfile=/var/log/supervisor/supervisord.log
[program:myapp]
command=/usr/bin/python3 /path/to/app.py
directory=/path/to/app
user=myuser
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/myapp.err.log
stdout_logfile=/var/log/supervisor/myapp.out.log命令:
# 启动 supervisord
supervisord -c /path/to/supervisord.conf
# 检查状态
supervisorctl status
# 启动程序
supervisorctl start myapp
# 停止程序
supervisorctl stop myapp
# 重启程序
supervisorctl restart myapp
# 重新读取配置
supervisorctl reread
supervisorctl update参考来源: Supervisor Official Documentation, Install supervisor on Mac M1
Circus
Circus 是 Supervisord 的现代 Python 替代方案,具有更好的性能和活跃的开发:
pip install circusCircus 配置(`circus.ini`):
[watcher:myapp]
cmd = python3 /path/to/app.py
uid = myuser
numprocesses = 1
autostart = true
stop_signal = TERM命令:
circusd circus.ini
circusctl status
circusctl start myapp
circusctl stop myapp相对于 Supervisord 的优势:
• 使用 ZeroMQ 获得更好的性能
• 对进程变化响应更灵敏
• 活跃的开发
• 跨平台
参考来源: Circus Documentation
基于 Procfile 的管理器
Overmind
Overmind 是一个使用 tmux 实现终端 UI 的现代进程管理器,非常适合具有多个进程的开发环境。
安装:
brew install overmindProcfile(`Procfile`):
web: bundle exec rails server
worker: bundle exec sidekiq
redis: redis-server使用:
overmind startOvermind 创建一个 tmux 会话,每个进程在其自己的窗口中,可通过标准 tmux 命令访问。
最适合: 开发环境、多进程应用程序、基于终端的工作流程。
参考来源: Overmind GitHub, Control Your Dev Processes with Overmind
Honcho(Python)和 Foreman(Ruby)
Honcho(Python):
pip install honcho
honcho startForeman(Ruby):
foreman start两者都使用与 Overmind 相同的 Procfile 格式 gem install for,但没有 tmux TUI。
其他方法
nohup
用于快速后台任务:
nohup node app.js &最适合: 快速测试、简单的后台任务、临时运行。
screen/tmux
用于持久的终端会话:
screen -S mysession
# 或
tmux new -s mysession最适合: 交互式会话、远程工作、长时间运行的终端进程。
综合对比:优缺点
工具 | 描述 | 优点 | 缺点 |
------ | ------ | ------ | ------ |
**launchd** | macOS 原生初始化系统 | ✅ 原生 macOS<br>✅ 无需安装<br>✅ surviving系统更新<br>✅ 最可靠的选项<br>✅ 完整系统集成 | ❌ XML 配置冗长<br>❌ 学习曲线陡峭<br>❌ 调试可能困难<br>❌ 社区工具有限 |
**brew services** | Homebrew 服务包装器 | ✅ 极其简单的界面<br>✅ 一键安装<br>✅ Homebrew 用户熟悉<br>✅ 自动生成 plist | ❌ 需要 Homebrew<br>❌ 自定义有限<br>❌ 不适合生产环境<br>❌ 隐藏的复杂性 |
**PM2** | Node.js 进程管理器 | ✅ 为 Node.js 而生<br>✅ 集群支持<br>✅ 出色的监控<br>✅ 崩溃时自动重启<br>✅ 零停机重载 | ❌ 特定于 Node.js<br>❌ 需要额外软件依赖<br>❌ 内存开销<br>❌ 功能学习曲线 |
**Forever** | 简单的 Node.js 保活 | ✅ 非常轻量<br>✅ 简单易用<br>✅ 资源占用低 | ❌ 功能极少<br>❌ 无监控仪表板<br>❌ 无集群<br>❌ 仅手动重启 |
**Supervisord** | Python 进程管理器 | ✅ 成熟稳定<br>✅ 语言无关<br>✅ Web 监控界面<br>✅ 进程分组 | ❌ 架构较老<br>❌ 配置复杂<br>❌ 比现代替代方案慢<br>❌ 开发不够活跃 |
**Circus** | 现代 Python 进程管理器 | ✅ 更好的性能<br>✅ ZeroMQ 通信<br>✅ 活跃开发<br>✅ 跨平台 | ❌ 社区较小<br>❌ 不如 Supervisord 成熟<br>❌ 配置格式不同<br>❌ 可用教程较少 |
**Overmind** | 基于 Procfile 的开发管理器 | ✅ 出色的 tmux TUI<br>✅ 标准 Procfile 格式<br>✅ 非常适合开发<br>✅ 可视化进程控制 | ❌ 依赖 tmux<br>❌ 不适合生产<br>❌ 需要终端访问<br>❌ macOS 特定 quirks |
**Honcho** | Python Procfile 管理器 | ✅ 跨平台<br>✅ 简单界面<br>✅ 纯 Python | ❌ 无 TUI<br>❌ 不如 Overmind 流行<br>❌ 功能极少 |
**Foreman** | Ruby Procfile 管理器 | ✅ 原始 Procfile 工具<br>✅ 经过实战考验<br>✅ 庞大社区 | ❌ 依赖 Ruby<br>❌ 代码库老旧<br>❌ 无 TUI<br>❌ 比替代方案慢 |
**cron** | Unix 作业调度器 | ✅ 熟悉的语法<br>✅ 快速任务简单<br>✅ 适用于所有 Unix | ❌ 在 macOS 上已被弃用<br>❌ 无原生 macOS 集成<br>❌ 错误处理差<br>❌ 睡眠/唤醒处理不佳 |
**nohup** | Unix 后台命令 | ✅ 内置 Unix<br>✅ 无需安装<br>✅ 测试快速 | ❌ 无自动重启<br>❌ 无监控<br>❌ 终端关闭时丢失<br>❌ 仅手动进程管理 |
**screen/tmux** | 终端多路复用器 | ✅ 持久会话<br>✅ 非常适合远程工作<br>✅ 多个窗口 | ❌ 不适合自动化<br>❌ 需要终端访问<br>❌ 手动进程管理<br>❌ 基于会话(非服务) |
决策框架
按使用场景选择
场景 | 推荐工具 | 原因 |
------ | ---------- | ------ |
生产系统服务 | launchd | 原生、可靠、重启后存活 |
使用 Procfile 开发 | Overmind | TUI、简单的进程管理 |
Node.js 生产环境 | PM2 | 集群、监控、自动重启 |
Node.js 简单/开发 | Forever | 简单、轻量 |
Python 生产环境 | Circus/Supervisord | Python 原生、成熟 |
数据库/Redis | brew services | 简单、Homebrew 集成 |
一次性后台任务 | nohup | 内置、无需设置 |
生产定时任务 | launchd | 原生、更多功能 |
跨平台开发 | Honcho | 到处可用 |
按技能水平选择
用户画像 | 从何开始 | 扩展到 |
---------- | ---------- | -------- |
关注 macOS 原生 | launchd | brew services |
Node.js 开发者 | PM2 | launchd 用于系统集成 |
Python 开发者 | Circus | brew services 用于数据库 |
DevOps 工程师 | launchd | Supervisord/Circus |
初学者 | brew services | PM2 或 launchd |
高级用户 | Overmind | 根据需要使用所有工具 |
集成策略
PM2 与 launchd:
pm2 startup darwin # 创建 launchd plist
pm2 save # 保存当前进程列表brew services 与 launchd: brew services 自动创建 launchd plist。
Overmind 与 Docker: 在本地使用 Overmind 进程,使用 Docker 容器,用脚本编排。
结论
macOS 为进程自动化提供了丰富的工具包:
1. 对于大多数用户:从 brew services 开始,因为它简单
2. 对于生产环境:直接使用 launchd 或通过工具集成(PM2 startup)
3. 对于 Node.js:PM2 是行业标准
4. 对于 Python:Supervisord 或 Circus
5. 对于开发环境:Overmind 提供出色的工作流程
关键是为您特定的用例和环境选择正确的工具。像 launchd 这样的原生工具提供与 macOS 最可靠的集成,而像 PM2 这样的特定语言工具为其生态系统提供专门的功能。
封面图片: 包含 launchd 架构、brew services 接口、PM2 仪表板和对比表的 macOS 自动化工具技术图表。
参考来源:
• Understanding macOS LaunchAgents
• Homebrew Services Guide
• PM2 Documentation
• Supervisor Documentation
• Overmind GitHub



