0

I have a product that is up for grabs. First claim is the first served, but the payment process can take a few seconds to finish and can fail. I am not sure how to approach this.

I am testing with this code, and I am sending two requests one after the other. The first one finishes successfully after the 5 seconds wait. The second one I would want it to wait for the first one to finish and then see that it is claimed already, instead it raises a doctrine lock exception.

$em = $this->getDoctrine()->getManager();

//here I would expect it to wait until the lock is released.
$product = $em->getRepository(Product::class)->find(1);

if($product->getStatus() == Product::STATUS_PENDING){

    $em->beginTransaction();
    $em->lock($product, LockMode::PESSIMISTIC_READ);

    try {
        sleep(5);
        if($paymentService->handlePayment($product)){
           $product->setStatus(Product::STATUS_CLAIMED);
           $em->persist($product);
           $em->flush(); 
           $em->commit();
        }else{
           $em->commit(); //to release the lock
          //throw payment error
        }
    } catch (\Exception $e) {
        $em->rollback();
        throw $e;
    }

    die("success");

}else{

    die("already sold");

}

What is the best approach to this? Thanks!

Vlad Dogarescu
  • 153
  • 1
  • 11

1 Answers1

0

I found my answer here: https://stackoverflow.com/a/17721736

$em = $this->getDoctrine()->getManager();

$em->beginTransaction();
$product = $em->find(Product::class,1,LockMode::PESSIMISTIC_WRITE);

if($product->getStatus() == Product::STATUS_PENDING){

    $product->setStatus(Product::STATUS_CLAIMED);
    $product->setName($val);
    sleep(10);
    $em->persist($product);
    echo "done";

}else{
    echo "already sold";
}

$em->flush();
$em->commit();
Vlad Dogarescu
  • 153
  • 1
  • 11