当cron作业不足以满足需求时,我应该使用什么?(php)

10

我正在尝试找出每天运行数千次一个相当繁重的PHP任务的最有效方法。该任务需要与Gmail建立IMAP连接,遍历电子邮件,将这些信息保存到数据库中并将图像保存在本地。

使用cron定时运行此任务不是什么大问题,但我需要每分钟运行一次它,并且我知道最终cron会开始互相覆盖并导致内存问题。

当您需要高效地多次运行任务时,请采取下一步措施是什么?我一直在阅读有关beanstalk和pheanstalk的文章,但我并不确定它是否能够满足我的需求。 你有什么想法吗?


这与你的问题不直接相关,但可以使用CURL来检索图像。它会缓存DNS请求,而file_get_contents()和其他本地文件函数则不会。我曾经需要编写一个脚本来检索图像,几乎所有的执行时间都是网络延迟。因此,这可以帮助稍微减少一些延迟。 - Savageman
4个回答

10

我不是PHP专家,但是......有什么阻止你将脚本作为守护进程运行呢?我曾经编写过很多这样的perl脚本。

我不是PHP开发者,但是......有什么防止你将脚本作为守护进程运行的问题吗?我编写过许多类似的perl脚本。

我以前从未编写过守护进程,但现在我会开始做更多的研究。感谢您的建议。 - mike
基本上……你只需要把所有内容都包裹在 while(1) 中,并将脚本在后台运行即可。如果它完成某些事情比仅仅被杀掉更重要,那么请了解信号处理,这样你就可以在退出之前进行清理。如果能使用 fork 而不是在 shell 后台运行,则会额外加分 :) - Brian Roach
我建议使用2个文件:第一个文件创建另一个进程来运行守护进程。第一个文件将等待几秒钟,然后检查守护进程是否仍在运行。如果没有运行,则可以重新启动它。我不太信任PHP长时间运行,因此我认为最好采取预防措施。 - Savageman
PHP脚本在长时间运行方面没有问题,我们这里有一些脚本可以连续运行数周而不出现问题。你不必喜欢PHP(我也不喜欢),但这种语言已经成熟了很多,现在非常稳定。 - user253984
@mike,即使你用PHP编写,也可以查看Perl的基本概念:http://search.cpan.org/~ehood/Proc-Daemon-0.03/Daemon.pm(使用双重分叉和其他系统工具,使其更加健壮)。 - Unreason
显示剩余2条评论

7

要么创建一个锁定机制,以使脚本不会重叠。由于脚本仅在每分钟运行一次,因此一个简单的.lock文件就足够了:

<?php
  if (file_exists("foo.lock")) exit(0);
  file_put_contents("foo.lock", getmypid());

  do_stuff_here();

  unlink("foo.lock");
?>

这将确保脚本不同时运行,您只需要确保在程序退出时删除.lock文件,因此您应该有一个单独的退出点(除了开始时的退出)。

另一个好的选择——就像Brian Roach建议的那样——是一个专用的服务器进程,它始终运行并保持与IMAP服务器的连接。 这大大降低了开销,并且与编写常规php脚本几乎没有区别:

<?php
  connect();
  while (is_world_not_invaded_by_aliens())
  {
    get_mails();
    get_images();
    sleep(time_to_next_check());
  }
  disconnect();
?>

2
我认为守护进程将是我的最佳选择,保持 IMAP 开启应该会使事情更快。谢谢你的建议! - mike

3

我有一些类似这样的脚本,我不想在cron中运行它们以防堆积。

#!/bin/sh
php -f fetchFromImap.php
sleep 60
exec $0
exec $0部分会重新启动脚本,将自己替换在内存中,这样它就可以一直运行而不会出问题。PHP脚本使用的任何内存都会在退出时清理,因此也不是问题。
一个简单的命令可以启动它,并将其放入后台:
cd /x/y/z ; nohup ./loopToFetchMail.sh &

或者可以通过各种方式(例如Cron的“@reboot ....”)在机器启动时类似地启动。


0

如果旧作业仍在运行,fcron http://fcron.free.fr/ 将不会启动新作业,您可以使用 @ 1 command 而不必担心竞争条件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接