job_queue 0
Web applications usually follow a synchronous communication model. However, non-interactive and long-running tasks (such as report generation) are better suited for asynchronous execution. One way to off-load tasks to run at a later time, or even on a different server, is use the Job Queue module available as a part of Zend Server 5 (though not as part of the Community Edition).
Web应用程序通常遵循同步通信模型。 但是,非交互式且长时间运行的任务(例如报告生成)更适合异步执行。 减轻任务的负担以在以后甚至在另一台服务器上运行的一种方法是使用Job Queue模块,它是Zend Server 5的一部分(尽管不是Community Edition的一部分)。
Job Queue allows job scheduling based on time, priority, and even dependencies. Jobs can be deferred or executed periodically and – the best part – run in parallel! On top of that, Zend Server itself provides a management GUI to track the execution of jobs including their status, execution time, and output.
Job Queue允许根据时间,优先级甚至依赖项来安排作业。 作业可以被延迟或定期执行,并且最好的部分是并行运行! 最重要的是,Zend Server本身提供了一个管理GUI来跟踪作业的执行情况,包括其状态,执行时间和输出。
The main advantage of the Job Queue module is its ability to execute tasks in parallel. Unlike cron jobs, Job Queue allows:
Job Queue模块的主要优点是能够并行执行任务。 与cron作业不同,Job Queue允许:
- Running tasks now without waiting for them to finish (asynchronous execution) 现在正在运行任务,而无需等待它们完成(异步执行)
- Running tasks once but not right now (deferred jobs) 运行一次任务,但现在不运行(延迟的作业)
- Running tasks periodically (recurring jobs like cron, but with full control over them from through the PHP API – start, stop, suspend, resume) 定期运行任务(重复执行的任务,例如cron,但可以通过PHP API对其进行完全控制-启动,停止,挂起,恢复)
- Ability to query job status, handle failures, and re-queue via the API as well as keep track of past, current, and pending jobs from the GUI. 能够通过API查询作业状态,处理故障和重新排队,以及从GUI跟踪过去,当前和待处理的作业。
Some examples of asynchronous tasks where Job Queue can be helpful are:
Job Queue可以帮助您完成一些异步任务,例如:
- Preparing data for the next request (pre-calculating) 为下一个请求准备数据(预先计算)
- Pre-caching data 预缓存数据
- Generating periodical reports 生成定期报告
- Sending e-mails 发送邮件
- Cleaning temporary data or files 清理临时数据或文件
- Communicating with external systems 与外部系统通讯
- Background data synchronization with mobile devices 与移动设备的后台数据同步
作业队列的使用 (Job Queue Usage)
Job Queue’s API is made available through the ZendJobQueue
class. To perform most tasks you will connect to a Job Queue server by instantiating a ZendJobQueue
object and create a job using the createHttpJob()
method.
可通过ZendJobQueue
类使用Job Queue的API。 要执行大多数任务,您将通过实例化ZendJobQueue
对象连接到Job Queue服务器,并使用createHttpJob()
方法创建作业。
<?php
$queue = new ZendJobQueue();
$queue->createHttpJob("http://example.com/jobs/somejob.php");
Passing a path to createHttpJob()
instead of a full URL will create a job with the value of $_SERVER["HTTP_HOST"]
as the host name. Watch out for instances when $_SERVER["HTTP_HOST"]
is not available, such as when the job is scheduled from a cron script.
传递路径到createHttpJob()
而不是完整URL将创建一个作业,其值为$_SERVER["HTTP_HOST"]
作为主机名。 当$_SERVER["HTTP_HOST"]
不可用时,请当心实例,例如从cron脚本调度作业时。
<?php
// both calls are equivalent
$queue->createHttpJob("/jobs/somejob.php");
$queue->createHttpJob("http://" . $_SERVER["HTTP_HOST"] . "/jobs/somejob.php");
Job parameters can be passed either as a part of the query string or in an array as the second argument of createHttpJob()
. If parameters are passed as the second argument, the array must be JSON compatible.
Job参数既可以作为查询字符串的一部分传递,也可以作为createHttpJob()
的第二个参数createHttpJob()
给数组。 如果将参数作为第二个参数传递,则数组必须与JSON兼容。
To access the parameters, the getCurrentJobParams()
static method can be used inside the job code.
要访问参数,可以在作业代码内部使用getCurrentJobParams()
静态方法。
<?php
$params = ZendJobQueue::getCurrentJobParams();
Additional job options are available via a third argument to createHttpJob()
. It is an associative array with the following keys:
其他作业选项可通过createHttpJob()
的第三个参数获得。 它是一个具有以下键的关联数组:
name
– an optional job namename
–可选的工作名称priority
– the job priority as defined by the corresponding constantsPRIORITY_LOW
,PRIORITY_NORMAL
,PRIORITY_HIGH
, andPRIORITY_URGENT
priority
–作业优先级,由相应的常量PRIORITY_LOW
,PRIORITY_NORMAL
,PRIORITY_HIGH
和PRIORITY_URGENT
persistent
– a Boolean value whether to keep the job in history foreverpersistent
-布尔值,是否将工作永久保留在历史记录中predecessor
– an integer predecessor job IDpredecessor
–整数前任工作IDhttp_headers
– additional HTTP headershttp_headers
–其他HTTP标头schedule
– cron-like scheduling commandschedule
–类似cron的调度命令schedule_time
– time when the job should be executed (but it may actually run after that time depending on Job Queue’s load)schedule_time
作业应执行的时间(但可能在此时间之后实际运行,具体取决于作业队列的负载)
For example, creating a deferred or recurring job would look like the examples below:
例如,创建一个递延或重复的工作将类似于以下示例:
<?php
$params = array("p1" => 10, "p2" => "somevalue");
// process in one hour
$options = array("schedule_time" => date("Y-m-d H:i:s", strtotime("+1 hour")));
$queue->createHttpJob("http://example.com/jobs/somejob.php", $params, $options);
// process every other day at 1:05 am
$options = array("schedule" => "5 1 */2 * *");
$queue->createHttpJob("http://example.com/jobs/somejob.php", $params, $options);
Failures (and successes) can be handled in the following manner:
失败(和成功)可以通过以下方式处理:
<?php
try {
doSomething();
ZendJobQueue::setCurrentJobStatus(ZendJobQueue::OK);
}
catch (Exception $e) {
ZendJobQueue::setCurrentJobStatus(ZendJobQueue::STATUS_LOGICALLY_FAILED, $e->getMessage());
}
扩展示例 (An Extended Example)
Let’s say your web application has to generate and e-mail a set of reports upon a user’s request.
假设您的Web应用程序必须根据用户的请求生成并通过电子邮件发送一组报告。
Typically, given the fact that PHP does not support multiprocessing and synchronous communication model is used, the user will have to wait until all of the requested reports are generated one by one and e-mailed.
通常,考虑到PHP不支持多处理并且使用了同步通信模型这一事实,用户将不得不等到所有请求的报告一张一张地生成并通过电子邮件发送出去。
Using Job Queue in this case will not only allow the user to perform other actions with the application (since the work will be done asynchronously) but also the application can process multiple reports at the same time (since jobs can be executed in parallel) – so most of the reports (if not all) will finish at about the same time.
在这种情况下,使用Job Queue不仅将允许用户对应用程序执行其他操作(因为工作将异步完成),而且应用程序可以同时处理多个报告(因为作业可以并行执行)–因此大多数报告(如果不是全部)将在大约同一时间完成。
<?php
function scheduleReport($reportList, $recipient) {
// list of scheduled jobs
$jobList = array();
$queue = new ZendJobQueue();
// check that Job Queue is running
if ($queue->isJobQueueDaemonRunning() && count($reportList) > 0) {
foreach ($reportList as $report) {
$params = array("type" => $report["type"],
"start" => $report["start"],
"length" => $report["length"],
"recipient" => $recipient);
$options = array("priority" => $report["priority"]);
// execute the job in two minutes unless the priority is urgent
if ($report["priority"] != ZendJobQueue::PRIORITY_URGENT) {
$options["schedule_time"] = date("Y-m-d H:i:s", strtotime("+2 minutes"));
}
$jobID = $queue->createHttpJob("http://example.com/jobs/report.php", $params, $options);
// add job ID to the list of successfully scheduled jobs
if ($jobID !== false) {
$jobList[] = $jobID;
}
}
return $jobList;
}
The scheduleReport()
function returns the list of job identifiers associated with each scheduled report. Within this function, the isJobQueueDaemonRunning()
method of ZendJobQueue
class verifies that the appropriate service is running and jobs can be scheduled.
scheduleReport()
函数返回与每个计划报告关联的作业标识符列表。 在此函数中, ZendJobQueue
类的isJobQueueDaemonRunning()
方法可验证适当的服务正在运行并且可以调度作业。
Depending on the report’s priority, the job can be scheduled to run immediately or two minutes later (in an effort to reduce the load on the server if many reports are requested at the same time). Once a job is scheduled, its ID is saved to the list of all successfully created jobs. It’s important to know a job’s ID in order to be able to monitor the job or even cancel it.
根据报告的优先级,可以安排作业立即运行或两分钟后运行(如果同时请求多个报告,则可以减少服务器的负载)。 计划作业后,其ID将保存到所有成功创建的作业的列表中。 重要的是要知道作业的ID,以便能够监视该作业甚至取消该作业。
There’s what the call to scheduleReport()
function looks like:
对scheduleReport()
函数的调用如下所示:
<?php
// setup request for a daily sales report and monthly financial report
$reportList = array(
array("type" => "sales",
"start" => "2011-12-09 00:00:00",
"length" => 1,
"priority" => ZendJobQueue::PRIORITY_URGENT),
array("type" => "finance",
"start" => "2011-11-01 00:00:00",
"length" => 30,
"priority" => ZendJobQueue::PRIORITY_NORMAL));
// schedule reports
$jobList = scheduleReport($reportList, "user@example.com");
// verify that reports were scheduled
if (empty($jobList)) {
// show error message
}
As mentioned earlier, it is also possible cancel a scheduled job. Once the job is in progress though it will be finished. Thus, if the priority of the request is not urgent, the user has two minutes to cancel the delivery of the scheduled report.
如前所述,也可以取消计划的作业。 作业一旦完成,便会完成。 因此,如果请求的优先级不是紧急的,则用户有两分钟的时间来取消计划报告的发送。
<?php
function cancelReport($jobID) {
$queue = new ZendJobQueue();
return $queue->removeJob($jobID);
}
if ($jobID !== false && cancelReport($jobID)) {
// the job was successfully removed from the queue
}
The cancelReport()
function simply removes the job from the queue of scheduled reports which have not yet started to run.
cancelReport()
函数只是将作业从尚未开始运行的预定报告队列中删除。
The job script then looks like this:
作业脚本如下所示:
<?php
function runReport() {
$params = ZendJobQueue::GetParamList();
try {
$report = prepareReport($params["type"], $params["start"], $params["length"]);
sendReport($params["recipient"], $report);
ZendJobQueue::setCurrentJobStatus(ZendJobQueue::OK);
}
catch (Exception $e) {
ZendJobQueue::setCurrentJobStatus(ZendJobQueue::STATUS_LOGICALLY_FAILED, $e->getMessage());
}
}
The runReport()
function finally prepares and sends the report based on provided parameters. After completion, the job status is set as successful (or logically failed if there was an error).
最后, runReport()
函数根据提供的参数准备并发送报告。 完成后,作业状态将设置为成功(或在发生错误时逻辑上失败)。
备择方案 (Alternatives)
Of course there are alternatives to Job Queue. Solutions like cron, pcntl_fork, or even something Java based via PHP/Java Bridge may or may not be worth looking into depending on your need. More interesting tools also exist, such as Gearman, node.js, and RabbitMQ.
当然,还有作业队列的替代方法。 诸如cron, pcntl_fork之类的解决方案,或者甚至是基于PHP / Java Bridge的基于Java的解决方案,根据您的需要可能不值得研究。 还存在更多有趣的工具,例如Gearman , node.js和RabbitMQ 。
摘要 (Summary)
While Zend Server’s Job Queue is not the only way to handle queues and parallel processing in PHP, it is an extremely straight-forward solution backed by “The PHP Company” and is very easy to start using. And with the growing success of Zend’s PHPCloud adoption of Job Queue should become even wide-spread.
虽然Zend Server的Job Queue并不是处理PHP中的队列和并行处理的唯一方法,但它是“ PHP公司”支持的极其简单的解决方案,并且非常容易上手。 随着ZendPHPCloud的日益成功,Job Queue的采用应该变得更加广泛。
If you want to view the example code from this article in its entirety, you can find it on GitHub.
如果您想完整地阅读本文中的示例代码 ,可以在GitHub上找到它。
Image via Varina and Jay Patel/Shutterstock
图片来自Varina和Jay Patel / Shutterstock
job_queue 0