You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Procmail导致平台崩溃并实现单进程运行?

解决Procmail批量邮件涌入时多进程崩溃问题

要让Procmail每次仅运行一个进程,核心是通过排他锁限制实例数量,同时调整邮件处理逻辑避免子进程泛滥。以下是具体方案:

1. 修改Procmail配置,添加全局排他锁

通过目录锁(原子操作,可靠性更高)确保同一时间只有一个Procmail实例执行邮件处理流程。修改后的配置如下:

SHELL = /bin/sh
LOGFILE     = /var/log/procmail.log
LOGABSTRACT = "all"
VERBOSE     = "on"

# 创建全局排他锁目录(原子操作,仅第一个进程能成功创建)
:0:
* ? mkdir /var/lock/procmail_global_lock 2>/dev/null
{
    # 去掉原规则的"c"标志(避免启动子进程并行处理),改为串行执行脚本
    :0
    | php /srv/platform/laravel/artisan platform:catchemail >> /var/log/procmail_catchemail.log 2>&1

    # 投递邮件到日志文件(带锁确保写入安全)
    :0:
    /var/log/platform_catchemail
}

# 清理锁目录(进程正常退出时执行,防止异常锁残留)
:0
* ? rmdir /var/lock/procmail_global_lock 2>/dev/null

关键修改说明:

  • 目录锁机制:mkdir是原子操作,后续进程会因目录已存在而等待锁释放,确保单实例运行。
  • 移除c标志:原规则的:0c会创建子进程并行处理邮件,去掉c后改为串行处理,减少进程数量。
  • 锁目录清理:rmdir仅在目录为空时执行,避免异常退出后锁残留导致后续进程无法启动。

2. 额外优化:避免PHP脚本生成子进程

如果platform:catchemail artisan命令本身会生成子进程,需要在脚本内部添加锁机制(比如PHP的flock文件锁),确保同一时间只有一个脚本实例运行:

// 在artisan命令的handle方法开头添加锁逻辑
$lockFile = fopen('/var/lock/catchemail_script.lock', 'w');
if (!flock($lockFile, LOCK_EX | LOCK_NB)) {
    // 已有实例运行,直接退出
    exit(0);
}

// 原脚本逻辑...

// 脚本结束后释放锁
flock($lockFile, LOCK_UN);
fclose($lockFile);

3. 进阶方案:队列化处理

如果批量邮件量极大,推荐将Procmail改为仅负责邮件暂存,用单进程定时脚本处理队列:

Procmail配置修改(仅存队列):

SHELL = /bin/sh
LOGFILE     = /var/log/procmail.log
LOGABSTRACT = "all"
VERBOSE     = "on"

# 将邮件暂存到队列目录(带锁确保写入安全)
:0:
/var/spool/procmail_queue/

定时处理脚本(通过Cron执行):

添加Cron任务,每分钟运行一次单进程脚本处理队列:

* * * * * php /srv/platform/laravel/artisan platform:process_queue >> /var/log/procmail_queue.log 2>&1

这样Procmail仅做快速投递,实际邮件处理由单进程脚本串行完成,彻底避免多进程资源耗尽问题。

内容的提问来源于stack exchange,提问作者alex spencer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 08:40:33