2014-02-05 1 views
2

현재 웹 프론트 엔드의 병렬 작업/요청을 처리하는 기어 맨을 테스트 중입니다. 기어맨 클린트는 Ajax를 통해 게시 매개 변수로 요청을 수신 한 다음 작업을 생성하고 gearman worker에게 보냅니다. 동시에 여러 클라이언트의 다중 요청을 처리하기 위해 21 개의 작업자 프로세스 인스턴스가 실행됩니다. 한 번에 하나의 클라이언트 요청으로 모든 것이 잘 작동하지만, 동시에 여러 클라이언트가 요청할 경우 클라이언트는 요청한 정보에 대해 잘못된 결과를 얻습니다. 예를 들어 클라이언트 A가 customer_id 123에 대한 정보를 요청하고 클라이언트 B가 customer_id 456에 대한 정보를 요청하고 동시에 두 요청이 모두 실행되면 클라이언트 A는 클라이언트 B의 결과를 얻고 클라이언트 B는 클라이언트 A의 결과를 얻습니다. 다른 근로자의 기능을 분리하지만 동일한 문제가 존재합니다. 내 코드에서 문제를 찾을 수 있도록 도와주세요.기어맨 PHP 병렬 작업이 잘못된 요청에 응답했습니다.

나는 문제가없는 CURL-multi를 사용했으나 (최근에 기어를 시험해보고 더 많은 성능을 얻을 수 있는지 알아보기로 결정했습니다. 여기

는 클라이언트와 노동자에 대한 내 코드입니다 :

클라이언트 코드 :

<?php 

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past 
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 
header("Cache-Control: post-check=0, pre-check=0", false); 
header("Pragma: no-cache"); 


$order_id = $_POST['order_id']; 
$customer_id = $_POST['customer_id']; 

//some validation code here 


class DataCollector extends GearmanClient{ 
    private $data  = array(); 
    private $tmpArr = array(); 

    function addData($content){ 
     if($content){ 
      $this->tmpArr = json_decode($content, true); 
      $this->data  = array_merge($this->tmpArr, $this->data); 
      //$this->data[] = json_decode($content, true); 
     } 
    } 
    function getData(){ 
     return $this->data; 
    } 
    function outputData(){ 
     echo json_encode($this->getData()); 
    } 

    function taskCompleted($task){ 

     $this->addData($task->data()); 

    } 

} 


$collector = new DataCollector(); 

$collector->addServer(); 

# set a function to be called when the work is complete 
$collector->setCompleteCallback(array($collector, "taskCompleted")); 


//params to pass to worker 
$queryStr = array(
     "order_id" => $order_id, 
     "customer_id" => $customer_id 
); 

$postData = serialize($queryStr); 

# add tasks to be executed in parallel in Gearman server 
$collector->addTask("getdata_orderDetails", $postData, null, "1"); 
$collector->addTask("getdata_customerDetails", $postData, null, "2"); 

# run the tasks in parallel 
$collector->runTasks(); 


# output the data 
$collector->outputData(); 

?> 

작업자 코드 :

<?php 

class Worker{ 
    private $worker; 
    static $conn; 

public function __construct(){ 

    try{ 
     self::$conn = oci_connect($user, $pass, $db); // create db connection 
    } 
    catch (Exception $e) { 
     echo "ERROR: " . $e->getMessage(); 
    } 

    $this->worker = new GearmanWorker(); 
    $this->worker->addServer(); 

    # Register functions 
    $this->worker->addFunction("getdata_orderDetails", array($this, "getdata_orderDetails_fn")); 
    $this->worker->addFunction("getdata_customerDetails", array($this, "getdata_customerDetails_fn")); 
} 

public function run(){ 

    while (1) { 
     //print "Waiting for job...\n"; 
     $this->worker->work(); 
     if ($this->worker->returnCode() != GEARMAN_SUCCESS) { 
     echo "return_code: " . $this->worker->returnCode() . "\n"; 
     break; 
     } 
    } 



} 


static function getdata_orderDetails_fn($job){ 


     if(!self::$conn){ 
     $responseArr = array(
      'response_status'   => -1,   //failed 
      'response_message'   => 'Database connection lost', 
      'response_id'    => 'DatabaseConnectionErr' 
      ); 

     return json_encode($responseArr); 
     } 

    $postData = unserialize($job->workload()); 

    $order_id = $postData['order_id']; 
    $customer_id = $postData['customer_id']; 

    $sql = "select order_id, order_status, create_date from customer_order where order_id= :order_id"; 
    $stmt = oci_parse(self::$conn, $sql); 
    oci_bind_by_name($stmt, ":order_id", $order_id, -1); 
    oci_execute($stmt); 
    oci_fetch($stmt); 
    $order_id = oci_result($stmt, 'ORDER_ID'); 
    $order_status = oci_result($stmt, 'ORDER_STATUS'); 
    $create_date = oci_result($stmt, 'CREATE_DATE'); 
    oci_free_statement($stmt); 


    $responseArr = array(
     'response_status' => 1, 
     'response_message' => 'success', 
     'response_id'  => 'order_details', 
     'order_id'   => $order_id, 
     'order_status'  => $order_status, 
     'create_date'   => $create_date 
    ); 

    // send result 
    return json_encode($responseArr); 
} 

static function getdata_customerDetails_fn($job){ 


     if(!self::$conn){ 
     $responseArr = array(
      'response_status' => -1,   //failed 
      'response_message' => 'Database connection lost', 
      'response_id'  => 'DatabaseConnectionErr' 
      ); 

     return json_encode($responseArr); 
     } 

    $postData = unserialize($job->workload()); 

    $order_id = $postData['order_id']; 
    $customer_id = $postData['customer_id']; 

    $sql = "select customer_id, customer_fname, customer_lname, customer_address, customer_contact where customer_id= :customer_id"; 
    $stmt = oci_parse(self::$conn, $sql); 
    oci_bind_by_name($stmt, ":customer_id", $customer_id, -1); 
    oci_execute($stmt); 
    oci_fetch($stmt); 
    $customer_id  = oci_result($stmt, 'CUSTOMER_ID'); 
    $customer_fname  = oci_result($stmt, 'CUSTOMER_FNAME'); 
    $customer_lname  = oci_result($stmt, 'CUSTOMER_LNAME'); 
    $customer_address = oci_result($stmt, 'CUSTOMER_ADDRESS'); 
    $customer_contact = oci_result($stmt, 'CUSTOMER_CONTACT'); 
    oci_free_statement($stmt); 

    $responseArr = array(
     'response_id'  => 'customer_details', 
     'response_status' => 1, 
     'response_message' => 'success', 
     'customer_id'  => $customer_id, 
     'customer_fname' => $customer_fname, 
     'customer_lname' => $customer_lname, 
     'customer_address' => $customer_address, 
     'customer_contact' => $customer_contact 
    ); 

    // send result 
    return json_encode($responseArr); 

} 

}//class 


//start worker 
    $worker = new Worker(); 
    $worker->run(); 


?> 

답변

0

나는 Gearman을 그룹에서 도움을 받고 후 문제를 해결했습니다 $ postData를 기반으로 각 작업을 고유하게 만듭니다. 두 개 이상의 클라이언트가 동일한 정보 (예 : order_id 또는 customer_id)를 요청하면 gearman은 동일한 고유 작업 ID로 동시 요청을 대기열에 넣고 동일한 결과 (즉, 하나의 요청 만 처리됨)로 응답합니다.

$collector->addTask("getdata_orderDetails", $postData, null, md5($order_id); 
$collector->addTask("getdata_customerDetails", $postData, null, md5($customer_id); 
1

나는 문제가 당신의 작업 ID가 고유하지 않은 것을 믿는다 . 각 작업에 고유 ID를 할당하려고, 또는 모든 작업 ID를 지정하지 : https://groups.google.com/forum/m/#!topic/gearman/q3EV7mvHKDs

내 경우에 대한 해결책은 다음과 같습니다

$collector->addTask("getdata_orderDetails", $postData); 
$collector->addTask("getdata_customerDetails", $postData); 

# run the tasks in parallel 
$collector->runTasks(); 
+0

감사합니다. 당신은 라이트입니다. https://groups.google.com/forum/m/#!topic/gearman/q3EV7mvHKDs –

+0

답변도 정확하지만 제 시나리오의 경우 $를 기준으로 작업 고유 ID를 생성하는 것이 더 좋습니다. postData, 아래 내 대답을 참조하십시오. –

관련 문제