打破Gearman循环

时间:2015-03-27 16:40:59

标签: php gearman

我有一个php应用程序,可以从我们的服务器获取部件号请求。在那一刻,我们联系第三方API以收集定价信息,以确保我们拥有该特定请求的最新定价。有时第三方API速度很慢或者可能已关闭,因此我们有一个数据库,可存储我们可用作后备的每个特定部件号的最新定价请求。我想使用Gearman并行地向第三方API和数据库运行请求。这是一个想法:

  1. 接收请求
  2. 通过齿轮工,创造两个工作:
    • 请求第三方API
    • MySQL数据库查找
  3. 等待循环并根据以下条件返回结果:
    • 如果第三方API已完成返回该结果,请立即返回该结果
    • 如果已经过了经过的时间(例如2秒)并且第三方API没有响应,则返回MySQL查找数据
  4. 使用gearman,我的想法是在前台运行两个任务并在setCompleteCallback()调用中中断runTasks(),或者在后台运行它们并在单独的循环中检查两个任务并使用jobStatus()检查任务。

    不幸的是,我无法获得任何一条路由,但仍能访问结果数据。有没有更好的方法,或者是否存在某些人如何使这项工作成为现实的例子?

1 个答案:

答案 0 :(得分:0)

我认为您已经描述了单个阻止问题,即第三方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查找成功。

这个想法是在worker任务中设置超时条件,这完全取决于你如何实现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