从 Linux 上的 Web 环境安排作业

发布于 2024-10-09 07:17:28 字数 263 浏览 8 评论 0原文

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

我知道很多人会推荐 cron 和 at,但首先我不需要重复(cron),其次也是最重要的是,我需要能够扩展的解决方案。 At 的设计并未考虑竞争条件,如果两个用户尝试同时添加一项作业,其中一个或两个可能会失败。

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

有人可以建议这项任务的解决方案吗?谢谢。

I am developing an application in PHP on Linux/Apache. I want to be able to schedule PHP jobs (scripts) for execution at some specific time in the future from within the application.

I know that many people will recommend cron and at, but first of all I don't need recurrence (cron) and secondly and most importantly, I need the solution to be able to scale. At was not designed with race condititions in mind, and if two users try to add a job at the same time one or both may fail.

It's also important that jobs are executed at their specified time, and not just 'polled' once per minute or so.

Can anyone please suggest solutions for this task? Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

热血少△年 2024-10-16 07:17:28

编写一个 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

write a php-script as a daemon
the script runs in the background, wakes up every some microseconds, checks for tasks to execute. if it has some tasks to execute, it could then fork itself and start the task.

if you don't like, that the script wakes up every some microseconds, you could also calculate the usleep time to the next task and then fork to start it. when tasks are being added or deleted, just send signal to the program and it then wakes up and recalculates how long it has to sleep now.

hyperlinks:

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

2024-10-16 07:17:28

你可以尝试 gearman

you can try gearman

姐不稀罕 2024-10-16 07:17:28

您可以(我会)这样做:

This is what you could(I would) do:

以可爱出名 2024-10-16 07:17:28

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

$ at 13:20 executeVeryImportantScript.php withPositionalParameters taken

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

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

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

On POSIX systems, there should be the at-daemon which is basically a one shot version of cron:

$ at 13:20 executeVeryImportantScript.php withPositionalParameters taken

which could be called via php's exec (or whatever is used to execute shell commands via php).

Reimplementing already existing solutions is Very Bad Practise ™:

  1. You need to implement it, which is not cost efficient
  2. You need to test the code
  3. You need to maintain the code
何止钟意 2024-10-16 07:17:28

这是使用 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) {

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

Here is a solution for Yii2 using MySQL. If you put the query/status update in a transaction, you can have multiple workers on different machines.

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);
  }

Then you can have tasks in the class like

function toggleStatus($job, $id) {

which do the work and update the progress of the job as it completes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文