突破Gearman循环


Breaking out of a Gearman loop

我有一个php应用程序,它从我们的服务器获取零件号请求。此时,我们联系第三方API收集定价信息,以确保我们拥有该特定请求的最新定价。有时第三方API运行缓慢或可能出现故障,因此我们有一个数据库,用于存储每个特定零件号的最新定价请求,我们可以将其用作后备方案。我想使用Gearman并行运行对第三方API和数据库的请求。想法如下:

  1. 接收请求
  2. 通过gearman,创造两个就业机会:
    • 向第三方API提出请求
    • MySQL数据库查找
  3. 在循环中等待,并根据以下条件返回结果:
    • 如果第三方API已完成返回该结果,请立即返回该结果
    • 如果经过一段时间(例如2秒),第三方API没有响应,返回MySQL查找数据

使用gearman,我的想法是要么在前台运行这两个任务,并在setCompleteCallback()调用中中断runTasks(),要么在后台运行它们,并在一个单独的循环中签入两个任务并使用jobStatus()签入任务。

不幸的是,在仍然可以访问结果数据的情况下,我无法获得任何一条上班路线。有没有更好的方法,或者有没有一些现有的例子说明有人是如何做到这一点的?

我认为您已经描述了一个单独的阻塞问题,即第三方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的包装器),您可以在这里看到如何检测超时的答案。

从工人方面来看:

$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