php: 8.1 doctrine: 2.9.2
I am having a problem implementing concurrency in doctrine. I've looked through the documentation and a few questions and I cannot see what my issue is.
My app is tracking inventory. There is a chance that multiple requests may update the stock at the same time. I put in a sleep to test. The 2nd request waits for the 1st request to finish, so the lock appears to be partially working. However, the 2nd request uses the starting stock instead of the adjusted stock of the 1st request.
Here is the persistence code:
$this->em->beginTransaction();
try{
$inventoryID = $stockAdjustment->getInventory()->getId();
$this->detach($stockAdjustment->getInventory());
$inventory = $this->inventoryRepo->find($inventoryID, LockMode::PESSIMISTIC_WRITE);
$this->refresh($inventory);
sleep(15);
$stockAdjustment->setInventory($inventory);
$stockAdjustment->setPreAdjustmentStock($inventory->getStock());
$inventory->modifyStock($stockAdjustment->getQuantity());
$this->em->persist($inventory);
$this->em->persist($stockAdjustment);
$this->em->flush();
$this->em->commit();
}
catch (\Throwable $e){
$this->em->rollback();
throw $e;
}
Before this occurs, the inventory is found when hydrating the adjustment. I left in the detach and refresh lines to show that I've tried that. Normally, Inventory is mapped to InventoryAdjustment with cascade persist. In this case, I've removed the cascade persist and am saving the inventory directly.
It was a stupid mistake that I realized just after posting. Stock can be a couple different types depending on the type of inventory, so stock is not actually stored on the Inventory object. I have another class InventoryStock and putting the lock on that resolved the issue. InventoryStock has a discriminator map for a few sub classes, but putting the lock on InventoryStock worked.