Skip to main content

macOS 进程自动化方法概览

![封面图片](@assets/images/overview-of-macos-process-automation-methods-cover.webp)

javascript typescript angular python ai

macOS 进程自动化方法概览

封面图片

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 服务
PM2Node.jsNode.js 生产环境
ForeverNode.js简单 Node.js
SupervisordPythonPython/任意语言
CircusPython现代 Python
OvermindProcfile开发环境
cronUnix 调度器传统任务

原生 macOS:launchd

什么是 launchd

launchd 是 macOS 的初始化系统和服务管理器,等效于 Linux 上的 systemd。它于 Mac OS X 10.4(Tiger)中引入,负责管理守护进程、代理和定时任务。macOS 上的每个进程(除内核外)最终都是 launchd 的子进程。

核心组件:

  • launchd - 系统服务管理器
  • launchctl - 用于管理服务的命令行接口
  • LaunchAgents - 用户级服务(用户登录时运行)
  • LaunchDaemons - 系统级服务(启动时运行,以 root 身份)

launchctl 命令参考

Terminal window
# 列出所有已加载的服务
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 debug

LaunchAgents 与 LaunchDaemons 的区别

LaunchAgents 和 LaunchDaemons 之间的区别是根本性的:

方面LaunchAgentsLaunchDaemons
运行时机用户登录时系统启动时
运行身份登录用户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. 检查语法:
Terminal window
plutil -lint ~/Library/LaunchAgents/com.example.service.plist
  1. 查看系统日志:
Terminal window
log show --predicate 'process == "launchd"' --last 1h
log stream --predicate 'eventMessage contains "com.example"'
  1. 检查服务状态:
Terminal window
launchctl list | grep com.example
  1. 手动执行测试:
Terminal window
# 直接运行命令以查看错误
/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 语法的简单基于时间的任务:

Terminal window
# 编辑 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:

Terminal window
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

然后验证安装:

Terminal window
brew --version

什么是 brew services

brew services 是一个 Homebrew 扩展,用于简化后台服务管理。它包装了 launchd,为通过 Homebrew 安装的服务提供熟悉的接口。

Terminal window
# 列出所有服务
brew services list
# 启动服务
brew services start postgresql
# 停止服务
brew services stop redis
# 重启服务
brew services restart nginx
# 在前台运行服务(用于调试)
brew services run postgresql

brew services 如何使用 launchd

brew services 自动创建 launchd plist 文件:

  • 用户服务~/Library/LaunchAgents/
  • 系统服务/Library/LaunchDaemons/

例如,brew services start postgresql 会在 ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist 创建一个 plist。

常见使用场景

数据库:

Terminal window
brew install postgresql
brew services start postgresql
brew install mysql
brew services start mysql
brew install redis
brew services start redis

Web 服务器:

Terminal window
brew install nginx
brew services start nginx

开发环境栈:

Terminal window
# 启动多个服务
brew services start postgresql
brew services start redis
brew services start memcached

GUI 工具

对于喜欢图形界面的用户:

参考来源: Homebrew Services: How to Use, How It Works, Managing background processes in Ventura

Node.js 进程管理器

PM2

PM2 是 Node.js 生产环境进程管理的事实标准。它提供集群、监控和自动重启功能。

安装:

Terminal window
npm install pm2 -g

基本命令:

Terminal window
# 启动应用程序
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 在启动时自动运行:

Terminal window
# 生成并保存启动脚本
pm2 startup darwin
# 保存当前进程列表
pm2 save
# 现在启动您的应用
pm2 start app.js
pm2 save

pm2 startup darwin 命令会生成一个在系统启动时加载 PM2 的 launchd plist,而 pm2 save 会保存当前进程列表,以便 PM2 可以在重启后恢复您的应用程序。

参考来源: PM2 Documentation, How to use pm2 startup on macOS

Forever

对于更简单的使用场景,Forever 提供基本的保活功能:

Terminal window
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 - 文件更改时自动重启(仅限开发)
    Terminal window
    npm install -g nodemon
    nodemon app.js
  • concurrently - 同时运行多个 npm 脚本
    Terminal window
    npm install -g concurrently
    concurrently "npm run watch" "npm run serve"
  • nohup - 用于快速后台任务的内置 Unix 命令

Python 进程管理器

Supervisord

Supervisord 是一个成熟的 Unix 类系统进程控制系统,广泛用于 Python 环境。

安装:

Terminal window
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

命令:

Terminal window
# 启动 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 替代方案,具有更好的性能和活跃的开发:

Terminal window
pip install circus

Circus 配置(circus.ini):

[watcher:myapp]
cmd = python3 /path/to/app.py
uid = myuser
numprocesses = 1
autostart = true
stop_signal = TERM

命令:

Terminal window
circusd circus.ini
circusctl status
circusctl start myapp
circusctl stop myapp

相对于 Supervisord 的优势:

  • 使用 ZeroMQ 获得更好的性能
  • 对进程变化响应更灵敏
  • 活跃的开发
  • 跨平台

参考来源: Circus Documentation

基于 Procfile 的管理器

Overmind

Overmind 是一个使用 tmux 实现终端 UI 的现代进程管理器,非常适合具有多个进程的开发环境。

安装:

Terminal window
brew install overmind

Procfile(Procfile):

web: bundle exec rails server
worker: bundle exec sidekiq
redis: redis-server

使用:

Terminal window
overmind start

Overmind 创建一个 tmux 会话,每个进程在其自己的窗口中,可通过标准 tmux 命令访问。

最适合: 开发环境、多进程应用程序、基于终端的工作流程。

参考来源: Overmind GitHub, Control Your Dev Processes with Overmind

Honcho(Python)和 Foreman(Ruby)

Honcho(Python):

Terminal window
pip install honcho
honcho start

Foreman(Ruby):

foreman start

两者都使用与 Overmind 相同的 Procfile 格式 gem install for,但没有 tmux TUI。

其他方法

nohup

用于快速后台任务:

Terminal window
nohup node app.js &

最适合: 快速测试、简单的后台任务、临时运行。

screen/tmux

用于持久的终端会话:

Terminal window
screen -S mysession
# 或
tmux new -s mysession

最适合: 交互式会话、远程工作、长时间运行的终端进程。

综合对比:优缺点

工具描述优点缺点
launchdmacOS 原生初始化系统✅ 原生 macOS
✅ 无需安装
✅ surviving系统更新
✅ 最可靠的选项
✅ 完整系统集成
❌ XML 配置冗长
❌ 学习曲线陡峭
❌ 调试可能困难
❌ 社区工具有限
brew servicesHomebrew 服务包装器✅ 极其简单的界面
✅ 一键安装
✅ Homebrew 用户熟悉
✅ 自动生成 plist
❌ 需要 Homebrew
❌ 自定义有限
❌ 不适合生产环境
❌ 隐藏的复杂性
PM2Node.js 进程管理器✅ 为 Node.js 而生
✅ 集群支持
✅ 出色的监控
✅ 崩溃时自动重启
✅ 零停机重载
❌ 特定于 Node.js
❌ 需要额外软件依赖
❌ 内存开销
❌ 功能学习曲线
Forever简单的 Node.js 保活✅ 非常轻量
✅ 简单易用
✅ 资源占用低
❌ 功能极少
❌ 无监控仪表板
❌ 无集群
❌ 仅手动重启
SupervisordPython 进程管理器✅ 成熟稳定
✅ 语言无关
✅ Web 监控界面
✅ 进程分组
❌ 架构较老
❌ 配置复杂
❌ 比现代替代方案慢
❌ 开发不够活跃
Circus现代 Python 进程管理器✅ 更好的性能
✅ ZeroMQ 通信
✅ 活跃开发
✅ 跨平台
❌ 社区较小
❌ 不如 Supervisord 成熟
❌ 配置格式不同
❌ 可用教程较少
Overmind基于 Procfile 的开发管理器✅ 出色的 tmux TUI
✅ 标准 Procfile 格式
✅ 非常适合开发
✅ 可视化进程控制
❌ 依赖 tmux
❌ 不适合生产
❌ 需要终端访问
❌ macOS 特定 quirks
HonchoPython Procfile 管理器✅ 跨平台
✅ 简单界面
✅ 纯 Python
❌ 无 TUI
❌ 不如 Overmind 流行
❌ 功能极少
ForemanRuby Procfile 管理器✅ 原始 Procfile 工具
✅ 经过实战考验
✅ 庞大社区
❌ 依赖 Ruby
❌ 代码库老旧
❌ 无 TUI
❌ 比替代方案慢
cronUnix 作业调度器✅ 熟悉的语法
✅ 快速任务简单
✅ 适用于所有 Unix
❌ 在 macOS 上已被弃用
❌ 无原生 macOS 集成
❌ 错误处理差
❌ 睡眠/唤醒处理不佳
nohupUnix 后台命令✅ 内置 Unix
✅ 无需安装
✅ 测试快速
❌ 无自动重启
❌ 无监控
❌ 终端关闭时丢失
❌ 仅手动进程管理
screen/tmux终端多路复用器✅ 持久会话
✅ 非常适合远程工作
✅ 多个窗口
❌ 不适合自动化
❌ 需要终端访问
❌ 手动进程管理
❌ 基于会话(非服务)

决策框架

按使用场景选择

场景推荐工具原因
生产系统服务launchd原生、可靠、重启后存活
使用 Procfile 开发OvermindTUI、简单的进程管理
Node.js 生产环境PM2集群、监控、自动重启
Node.js 简单/开发Forever简单、轻量
Python 生产环境Circus/SupervisordPython 原生、成熟
数据库/Redisbrew services简单、Homebrew 集成
一次性后台任务nohup内置、无需设置
生产定时任务launchd原生、更多功能
跨平台开发Honcho到处可用

按技能水平选择

用户画像从何开始扩展到
关注 macOS 原生launchdbrew services
Node.js 开发者PM2launchd 用于系统集成
Python 开发者Circusbrew services 用于数据库
DevOps 工程师launchdSupervisord/Circus
初学者brew servicesPM2 或 launchd
高级用户Overmind根据需要使用所有工具

集成策略

PM2 与 launchd:

Terminal window
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 自动化工具技术图表。

参考来源: