Friday, 23 August 2019

Handle same function running and processing the same data at the same time

I have a php system that that allow customer to buy things (make an order) from our system using e-wallet (store credit).

here's the database example

**sales_order**
+--------+-------+----------+--------+--------------+-----------+
|order_id| price |product_id| status |already_refund|customer_id|
+--------+-------+----------+--------+--------------+-----------+
|   1    | 1000  |    1     |canceled|      1       |     2     |
|   2    | 2000  |    2     |pending |      0       |     2     |
|   3    | 3000  |    3     |complete|      0       |     1     | 
+--------+-------+----------+--------+--------------+-----------+

**ewallet**
+-----------+-------+
|customer_id|balance|
+-----------+-------+
|     1     | 43200 |
|     2     | 22500 |
|     3     | 78400 |
+-----------+-------+

table sales_order contain the order that customer made, the column already_refund is for a flag that canceled order already refunded.

I'm running a cron every 5 minutes to check if order with status pending can be canceled and after that it can refund the money to the customer ewallet

function checkPendingOrders(){
   $orders = $this->orderCollection->filter(['status'=>'pending']);
   foreach($orders as $order){
     //check if order is ready to be canceled
     $isCanceled = $this->isCanceled($order->getId());
     if($isCanceled === false) continue;
     if($order->getAlreadyRefund() == '0'){ // check if already refund
       $order->setAlredyRefund('1')->save();
       $this->refund($order->getId()); //refund the money to customer ewallet
     }
     $order->setStatus('canceled')->save();
   }
}

The problem the 2 different cron schedule can process the same data at the same time using this function and it will make the refund process can be called twice , so the customer will receive double refund amount. How can i handle this kind of problem, when a 2 same function running at the same time to process same data ? the if clause that i made can't handle this kind of issue

update

i've tried to use microtime in session as validation, so at the beginning i set the variable to contain the microtime , than when i stored in a unique session generated by order_id , and then i add a condition to match the microtime value with the session before running my refund function

function checkPendingOrders(){
   $orders = $this->orderCollection->filter(['status'=>'pending']);
   foreach($orders as $order){
     //assign unique microtime to session
     $mt = round(microtime(true) * 1000);
     if(!isset($_SESSION['cancel'.$order->getId()])) $_SESSION['cancel'.$order->getId()] = $mt;
     //check if order is ready to be canceled
     $isCanceled = $this->isCanceled($order->getId());
     if($isCanceled === false) continue;
     if($order->getAlreadyRefund() == '0'){ // check if already refund
       $order->setAlredyRefund('1')->save();
       //check if microtime is the same as the first one that running
       if($_SESSION['cancel'.$order->getId()] == $mt) $this->refund($order->getId()); //refund the money to customer ewallet
     }
     unset($_SESSION['cancel'.$order->getId()]);
     $order->setStatus('canceled')->save();
   }
}

but the problem still persist when i'm doing a strees test, because there is a case when the same function process the same data at the same microtime



from Handle same function running and processing the same data at the same time

No comments:

Post a Comment