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