Reduce lock contention
Change-Id: I029ed7bfb75a3a3fce1245790ae9362685e09897 Signed-off-by: smarcet <smarcet@gmail.com>
This commit is contained in:
parent
c08bee3ce6
commit
a30e62fa05
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php namespace libs\utils;
|
||||
/**
|
||||
* Copyright 2015 OpenStack Foundation
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -11,11 +11,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
namespace libs\utils;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Interface ITransactionService
|
||||
* @package libs\utils
|
||||
|
@ -25,10 +21,11 @@ interface ITransactionService
|
|||
/**
|
||||
* Execute a Closure within a transaction.
|
||||
*
|
||||
* @param Closure $callback
|
||||
* @param Closure $callback
|
||||
* @param int $isolationLevel
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function transaction(Closure $callback);
|
||||
public function transaction(Closure $callback, int $isolationLevel);
|
||||
}
|
|
@ -302,6 +302,7 @@ class SummitOrder extends SilverstripeBaseModel implements IQREntity
|
|||
}
|
||||
|
||||
public function setPaid(){
|
||||
Log::debug(sprintf("SummitOrder::setPaid order %s", $this->id));
|
||||
if($this->isPaid()){
|
||||
Log::warning(sprintf("SummitOrder %s is already Paid.", $this->getId()));
|
||||
return;
|
||||
|
|
|
@ -462,7 +462,7 @@ final class EventServiceProvider extends ServiceProvider
|
|||
if(!$event instanceof PaymentSummitRegistrationOrderConfirmed) return;
|
||||
$order_id = $event->getOrderId();
|
||||
Log::debug(sprintf("EventServiceProvider::PaymentSummitRegistrationOrderConfirmed: firing ProcessSummitOrderPaymentConfirmation for order id %s", $order_id));
|
||||
ProcessSummitOrderPaymentConfirmation::dispatch($order_id)->delay(now()->addMinutes(1));
|
||||
ProcessSummitOrderPaymentConfirmation::dispatch($order_id)->delay(now()->addSecond(10));
|
||||
});
|
||||
|
||||
Event::listen(NewMember::class, function($event){
|
||||
|
|
|
@ -1700,14 +1700,17 @@ final class SummitOrderService
|
|||
$owner = null;
|
||||
$ticket_type = $this->ticket_type_repository->getByIdExclusiveLock(intval($payload['ticket_type_id']));
|
||||
|
||||
if (is_null($ticket_type) || !$ticket_type instanceof SummitTicketType || $ticket_type->getSummitId() != $summit->getId())
|
||||
if (is_null($ticket_type) || !$ticket_type instanceof SummitTicketType || $ticket_type->getSummitId() != $summit->getId()) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket ticket type not found");
|
||||
throw new EntityNotFoundException("ticket type not found");
|
||||
}
|
||||
|
||||
// check owner
|
||||
if (isset($payload['owner_id'])) {
|
||||
Log::debug(sprintf("SummitOrderService::createOrderSingleTicket trying to get member by id %s", $payload['owner_id']));
|
||||
$owner = $this->member_repository->getById(intval($payload['owner_id']));
|
||||
if (is_null($owner)) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket owner not found");
|
||||
throw new EntityNotFoundException("owner not found");
|
||||
}
|
||||
}
|
||||
|
@ -1723,7 +1726,11 @@ final class SummitOrderService
|
|||
|
||||
if (is_null($attendee) && isset($payload['owner_email'])) {
|
||||
Log::debug(sprintf("SummitOrderService::createOrderSingleTicket trying to get attendee by email %s", $payload['owner_email']));
|
||||
$attendee = $summit->getAttendeeByEmail(trim($payload['owner_email']));
|
||||
$attendee = $this->attendee_repository->getBySummitAndEmail($summit, trim($payload['owner_email']));
|
||||
}
|
||||
|
||||
if(is_null($attendee) && isset($payload['attendee'])){
|
||||
$attendee = $payload['attendee'];
|
||||
}
|
||||
|
||||
if (is_null($attendee)) {
|
||||
|
@ -1732,21 +1739,27 @@ final class SummitOrderService
|
|||
//first name
|
||||
$first_name = isset($payload['owner_first_name']) ? trim($payload['owner_first_name']) : null;
|
||||
if (empty($first_name) && !is_null($owner)) $first_name = $owner->getFirstName();
|
||||
if (empty($first_name))
|
||||
if (empty($first_name)) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket owner firstname is null");
|
||||
throw new ValidationException("you must provide an owner_first_name or a valid owner_id");
|
||||
}
|
||||
// surname
|
||||
$surname = isset($payload['owner_last_name']) ? trim($payload['owner_last_name']) : null;
|
||||
if (empty($surname) && !is_null($owner)) $surname = $owner->getLastName();
|
||||
if (empty($surname))
|
||||
if (empty($surname)) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket owner surname is null");
|
||||
throw new ValidationException("you must provide an owner_last_name or a valid owner_id");
|
||||
}
|
||||
// mail
|
||||
$email = isset($payload['owner_email']) ? trim($payload['owner_email']) : null;
|
||||
|
||||
$company = isset($payload['owner_company']) ? trim($payload['owner_company']) : null;
|
||||
|
||||
if (empty($email) && !is_null($owner)) $email = $owner->getEmail();
|
||||
if (empty($email))
|
||||
if (empty($email)) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket owner email is null");
|
||||
throw new ValidationException("you must provide an owner_email or a valid owner_id");
|
||||
}
|
||||
|
||||
$attendee = SummitAttendeeFactory::build($summit, [
|
||||
'first_name' => $first_name,
|
||||
|
@ -1769,8 +1782,10 @@ final class SummitOrderService
|
|||
Log::debug(sprintf("SummitOrderService::createOrderSingleTicket order number %s", $order->getNumber()));
|
||||
$default_badge_type = $summit->getDefaultBadgeType();
|
||||
|
||||
if (is_null($default_badge_type))
|
||||
if (is_null($default_badge_type)) {
|
||||
Log::warning("SummitOrderService::createOrderSingleTicket default_badge_type is null");
|
||||
throw new ValidationException(sprintf("summit %s does not has a default badge type", $summit->getId()));
|
||||
}
|
||||
|
||||
$order->setPaymentMethodOffline();
|
||||
|
||||
|
@ -2719,6 +2734,7 @@ final class SummitOrderService
|
|||
|
||||
Log::debug(sprintf("SummitOrderService::processTicketData processing row %s", json_encode($row)));
|
||||
$ticket = null;
|
||||
$attendee = null;
|
||||
|
||||
if ($ticket_data_present) {
|
||||
Log::debug("SummitOrderService::processTicketData - has ticket data present ... trying to get ticket");
|
||||
|
@ -2764,9 +2780,12 @@ final class SummitOrderService
|
|||
|
||||
$attendee = SummitAttendeeFactory::build($summit, $payload, $member);
|
||||
|
||||
$this->attendee_repository->add($attendee, true);
|
||||
//$this->attendee_repository->add($attendee, true);
|
||||
$this->attendee_repository->add($attendee);
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_null($attendee)) {
|
||||
if (is_null($ticket)) {
|
||||
Log::debug(sprintf("SummitOrderService::processTicketData ticket is null, trying to create a new one"));
|
||||
|
||||
|
@ -2795,13 +2814,16 @@ final class SummitOrderService
|
|||
return;
|
||||
}
|
||||
|
||||
$order = $this->createOrderSingleTicket($summit, [
|
||||
'ticket_type_id' => $ticket_type->getId(),
|
||||
'owner_email' => $attendee->getEmail(),
|
||||
'owner_first_name' => $attendee->getFirstName(),
|
||||
'owner_last_name' => $attendee->getSurname(),
|
||||
'owner_company' => $attendee->getCompanyName(),
|
||||
]);
|
||||
$order = $this->createOrderSingleTicket($summit,
|
||||
[
|
||||
'ticket_type_id' => $ticket_type->getId(),
|
||||
'attendee' => $attendee,
|
||||
'owner_email' => $attendee->getEmail(),
|
||||
'owner_first_name' => $attendee->getFirstName(),
|
||||
'owner_last_name' => $attendee->getSurname(),
|
||||
'owner_company' => $attendee->getCompanyName(),
|
||||
]
|
||||
);
|
||||
|
||||
$ticket = $order->getFirstTicket();
|
||||
|
||||
|
@ -2828,6 +2850,7 @@ final class SummitOrderService
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (is_null($ticket)) {
|
||||
Log::warning("SummitOrderService::processTicketData ticket is null stop current row processing.");
|
||||
return;
|
||||
|
@ -2932,7 +2955,8 @@ final class SummitOrderService
|
|||
throw new ValidationException("need to set a value for external_registration_feed_api_key");
|
||||
}
|
||||
|
||||
IngestSummitExternalRegistrationData::dispatch(
|
||||
IngestSummitExternalRegistrationData::dispatch
|
||||
(
|
||||
$summit->getId(),
|
||||
$email_to
|
||||
);
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\TransactionIsolationLevel;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use libs\utils\ITransactionService;
|
||||
use Closure;
|
||||
|
@ -43,11 +46,12 @@ final class DoctrineTransactionService implements ITransactionService
|
|||
* Execute a Closure within a transaction.
|
||||
*
|
||||
* @param Closure $callback
|
||||
* @param int $isolationLevel
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function transaction(Closure $callback)
|
||||
public function transaction(Closure $callback, int $isolationLevel = TransactionIsolationLevel::READ_COMMITTED)
|
||||
{
|
||||
$retry = 0;
|
||||
$done = false;
|
||||
|
@ -75,15 +79,18 @@ final class DoctrineTransactionService implements ITransactionService
|
|||
// new entity manager
|
||||
$con = $em->getConnection();
|
||||
}
|
||||
|
||||
$con->setTransactionIsolation($isolationLevel);
|
||||
Log::debug("DoctrineTransactionService::transaction con->beginTransaction");
|
||||
$con->beginTransaction(); // suspend auto-commit
|
||||
$result = $callback($this);
|
||||
$em->flush();
|
||||
$con->commit();
|
||||
Log::debug("DoctrineTransactionService::transaction con->commit");
|
||||
$done = true;
|
||||
} catch (RetryableException $ex) {
|
||||
Log::warning("retrying ...");
|
||||
Registry::resetManager($this->manager_name);
|
||||
Log::warning("DoctrineTransactionService::transaction con->rollBack");
|
||||
$con->rollBack();
|
||||
Log::warning($ex);
|
||||
$retry++;
|
||||
|
@ -94,6 +101,7 @@ final class DoctrineTransactionService implements ITransactionService
|
|||
Log::warning("rolling back transaction");
|
||||
Log::warning($ex);
|
||||
$em->close();
|
||||
Log::warning("DoctrineTransactionService::transaction con->rollBack");
|
||||
$con->rollBack();
|
||||
throw $ex;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ final class EloquentTransactionService implements ITransactionService {
|
|||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function transaction(Closure $callback)
|
||||
public function transaction(Closure $callback, int $isolationLevel)
|
||||
{
|
||||
return DB::transaction($callback);
|
||||
}
|
||||
|
|
|
@ -115,12 +115,10 @@ final class OAuth2SummitTicketsApiTest extends ProtectedApiTest
|
|||
return $csv;
|
||||
}
|
||||
|
||||
public function testIngestTicketData($summit_id = 1){
|
||||
public function testIngestTicketData($summit_id = 21){
|
||||
$csv_content = <<<CSV
|
||||
id,number,attendee_email,attendee_first_name,attendee_last_name,attendee_company,ticket_type_name,ticket_type_id,badge_type_id,badge_type_name,Commander,VIP Access
|
||||
,,xmarcet+1@gmail.com,sebastian,marcet,pumant,Full Pass,,,,1,1
|
||||
,DEVSUMMIT2019_TICKET_5DEE50D8DC3B4768174853,,,,,,,,,1,0
|
||||
684,,xmarcet+2@gmail.com,,,,,,,,1,0
|
||||
attendee_email,attendee_first_name,attendee_last_name,ticket_type_name,badge_type_name,Bloomreach Connect Summit - Day 1,User Group - Day 2,Tech Track - Day 3,Partner Summit - Day 4
|
||||
smarcet+json12@gmail.com,Jason12,Marcet,General Admission,General Admission,1,1,1,1
|
||||
CSV;
|
||||
$path = "/tmp/tickets.csv";
|
||||
|
||||
|
|
Loading…
Reference in New Issue