跳出 Gearman 循环
Breaking out of a Gearman loop
我有一个 php 应用程序可以从我们的服务器获取部件号请求。届时,我们会联系第三方 API 以收集定价信息,以确保我们拥有该特定请求的最新定价。有时第三方 API 速度很慢或可能已关闭,因此我们有一个数据库存储每个特定零件号的最新定价请求,我们可以将其用作后备。我想 运行 向第三方 API 请求并使用 Gearman 并行处理数据库。这是想法:
- 接收请求
- 通过gearman,创建两个job:
- 请求第三方API
- MySQL 数据库查找
- 循环等待,return结果基于以下条件:
- 如果第三方API完成了return那个结果,return那个结果立即
- 如果经过一段时间(例如 2 秒)并且第三方 API 没有响应,return MySQL 查找数据
使用 gearman,我的想法是 运行 前台的两个任务并在 setCompleteCallback() 调用中突破 运行Tasks(),或者 运行它们在后台并在单独的循环中检查这两个任务,并使用 jobStatus() 检查任务。
不幸的是,我无法在仍然可以访问结果数据的同时为我工作。有没有更好的方法,或者是否有一些现有的例子说明有人是如何做到这一点的?
我认为您已经描述了一个单一的阻塞问题,即第 3 方 API 查找的结果。从我的角度来看,有两种方法可以处理这个问题,如果您确定 运行 超时,您可以完全中止尝试,或者您可以向客户报告您 运行超时但无论如何继续查找,只是为了更新您的本地缓存以防万一它的响应速度比您希望的慢。我将描述我将如何解决前一个问题,因为那样会更容易。
来自客户端:
$request = array(
'productId' => 5,
);
$client = new GearmanClient( );
$client->addServer( '127.0.0.1', 4730 );
$results = json_decode($client->doNormal('apiPriceLookup', json_encode( $request )));
if($results && property_exists($results->success) && $results->success) {
// Use local data
} else {
// Use fresh data
}
这将在作业服务器上创建一个函数名称为 'apiPriceLookup'
的作业,并将包含产品 ID 5
的工作负载数据传递给它。它将等待结果返回,并检查 success
属性。如果它存在并且为真,则 api 查找成功。
想法是在工作任务中设置超时条件,这完全取决于您如何实现 API 查找。如果您使用的是 cURL(或 cURL 的一些包装器),您可以查看如何检测超时的答案 here.
从工人方面:
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("apiPriceLookup", "apiPriceLookup", $count);
while ($worker->work());
function apiPriceLookup($job) {
$payload = json_decode($job->workload());
try {
$results = [
'data' => PerformApiLookupForProductId($payload->productId),
'success' => true,
];
} catch(Exception $e) {
$results = ['success' => false];
}
return json_encode($results);
}
这只是创建了一个 GearmanWorker
对象并为其订阅了 apiPriceLookup
的函数。每当客户端向作业服务器提交任务时,它都会调用函数 apiPriceLookup
。该函数调用另一个函数 PerformApiLookupForProductId
,应该编写该函数以便在发生超时条件时抛出异常。
我认为这不会考虑使用异常来控制逻辑流程,我认为超时条件通常是异常(或应该是)事件。例如,Guzzle 将抛出 GuzzleHttp\Exception\RequestException
when it has decided to timeout。
我有一个 php 应用程序可以从我们的服务器获取部件号请求。届时,我们会联系第三方 API 以收集定价信息,以确保我们拥有该特定请求的最新定价。有时第三方 API 速度很慢或可能已关闭,因此我们有一个数据库存储每个特定零件号的最新定价请求,我们可以将其用作后备。我想 运行 向第三方 API 请求并使用 Gearman 并行处理数据库。这是想法:
- 接收请求
- 通过gearman,创建两个job:
- 请求第三方API
- MySQL 数据库查找
- 循环等待,return结果基于以下条件:
- 如果第三方API完成了return那个结果,return那个结果立即
- 如果经过一段时间(例如 2 秒)并且第三方 API 没有响应,return MySQL 查找数据
使用 gearman,我的想法是 运行 前台的两个任务并在 setCompleteCallback() 调用中突破 运行Tasks(),或者 运行它们在后台并在单独的循环中检查这两个任务,并使用 jobStatus() 检查任务。
不幸的是,我无法在仍然可以访问结果数据的同时为我工作。有没有更好的方法,或者是否有一些现有的例子说明有人是如何做到这一点的?
我认为您已经描述了一个单一的阻塞问题,即第 3 方 API 查找的结果。从我的角度来看,有两种方法可以处理这个问题,如果您确定 运行 超时,您可以完全中止尝试,或者您可以向客户报告您 运行超时但无论如何继续查找,只是为了更新您的本地缓存以防万一它的响应速度比您希望的慢。我将描述我将如何解决前一个问题,因为那样会更容易。
来自客户端:
$request = array(
'productId' => 5,
);
$client = new GearmanClient( );
$client->addServer( '127.0.0.1', 4730 );
$results = json_decode($client->doNormal('apiPriceLookup', json_encode( $request )));
if($results && property_exists($results->success) && $results->success) {
// Use local data
} else {
// Use fresh data
}
这将在作业服务器上创建一个函数名称为 'apiPriceLookup'
的作业,并将包含产品 ID 5
的工作负载数据传递给它。它将等待结果返回,并检查 success
属性。如果它存在并且为真,则 api 查找成功。
想法是在工作任务中设置超时条件,这完全取决于您如何实现 API 查找。如果您使用的是 cURL(或 cURL 的一些包装器),您可以查看如何检测超时的答案 here.
从工人方面:
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("apiPriceLookup", "apiPriceLookup", $count);
while ($worker->work());
function apiPriceLookup($job) {
$payload = json_decode($job->workload());
try {
$results = [
'data' => PerformApiLookupForProductId($payload->productId),
'success' => true,
];
} catch(Exception $e) {
$results = ['success' => false];
}
return json_encode($results);
}
这只是创建了一个 GearmanWorker
对象并为其订阅了 apiPriceLookup
的函数。每当客户端向作业服务器提交任务时,它都会调用函数 apiPriceLookup
。该函数调用另一个函数 PerformApiLookupForProductId
,应该编写该函数以便在发生超时条件时抛出异常。
我认为这不会考虑使用异常来控制逻辑流程,我认为超时条件通常是异常(或应该是)事件。例如,Guzzle 将抛出 GuzzleHttp\Exception\RequestException
when it has decided to timeout。