从Linux上的Web环境调度作业

时间:2010-12-25 10:42:25

标签: php linux scalability scheduled-tasks

我正在Linux / Apache上用PHP开发应用程序。我希望能够在应用程序内的某个特定时间安排PHP作业(脚本)执行。

我知道很多人会推荐cron和at,但首先我不需要重复(cron),其次,最重要的是,我需要解决方案才能扩展。在设计时没有考虑到种族歧视,如果两个用户同时尝试添加一个作业,其中一个或两个可能会失败。

在指定的时间执行作业也很重要,而不是每分钟左右“轮询”一次。

有人可以为此任务建议解决方案吗?谢谢。

5 个答案:

答案 0 :(得分:2)

将php脚本编写为守护进程 脚本在后台运行,每隔几微秒唤醒一次,检查要执行的任务。如果它有一些要执行的任务,它可以自行分叉并启动任务。

如果您不喜欢,脚本每微秒唤醒一次,您还可以计算下一个任务的睡眠时间,然后分叉启动它。当添加或删除任务时,只需向程序发送信号然后唤醒并重新计算它现在要睡多久。

超链接:

http://en.wikipedia.org/wiki/Daemon_%28computer_software%29

http://php.net/manual/en/function.pcntl-fork.php

http://www.php.net/manual/en/function.pcntl-signal.php

答案 1 :(得分:0)

您可以尝试gearman

答案 2 :(得分:0)

这是你可以(我愿意)做的事情:

  • 使用Google's app engine Task Queue。它有一个慷慨的免费配额(定价平面也不差),它可以扩展,使用webhooks。我认为这是最容易实施的解决方案。
  • beanstalkd

答案 3 :(得分:0)

在POSIX系统上,应该有at-daemon,它基本上是cron的一次性版本:

$ at 13:20 executeVeryImportantScript.php withPositionalParameters taken

可以通过php的exec调用(或者用于通过php执行shell命令的任何东西)。

重新实现已有的解决方案非常糟糕的做法

  1. 您需要实施它,这不符合成本效益
  2. 您需要测试代码
  3. 您需要维护代码

答案 4 :(得分:0)

这是使用MySQL的Yii2的解决方案。如果将查询/状态更新放在事务中,则可以在不同的计算机上安装多个工作程序。

cron table
Field         | Type        
--------------+-------------
id            | int(11)     
execute_after | timestamp   
executed_at   | timestamp   
status        | int(11)     
progress      | int(11)     
action        | varchar(255)
parameter     | varchar(255)
result        | varchar(255)
Cron class
  /** This command waits for jobs to work on by polling the DB every 10s. TODO put this into Redis.
   * 
   */
  public function actionIndex()
  {
    do {
      $job = Cron::find()->where('execute_after < :now AND status = 0 ORDER BY id ASC', [':now'=>date(DATE_ATOM)])->one();
      if($job && method_exists($this, $job->action)){
        $job->status = 1;
        $job->save() or Yii::error($job->getErrors());
        $result = $this->{$job->action}($job, $job->parameter);
        $job->status = 2;
        $job->progress = 100;
        $job->executed_at = date(DATE_ATOM);
        $job->save() or Yii::error($job->getErrors());
      }
      sleep(10);
    } while (true);
  }

然后你可以在类中拥有任务,如

function toggleStatus($job, $id) {

完成工作并在工作完成时更新工作进度。