commit a30e62fa05d13cb2c3a20c1e41ae86f37b185237 Author: smarcet Date: Wed Oct 7 00:20:06 2020 -0300 Reduce lock contention Change-Id: I029ed7bfb75a3a3fce1245790ae9362685e09897 Signed-off-by: smarcet diff --git a/Libs/Utils/ITransactionService.php b/Libs/Utils/ITransactionService.php index 26a054f..0c8d049 100644 --- a/Libs/Utils/ITransactionService.php +++ b/Libs/Utils/ITransactionService.php @@ -1,4 +1,4 @@ -id)); if($this->isPaid()){ Log::warning(sprintf("SummitOrder %s is already Paid.", $this->getId())); return; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 4d3d794..608272b 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -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){ diff --git a/app/Services/Model/Imp/SummitOrderService.php b/app/Services/Model/Imp/SummitOrderService.php index d9cfb60..a964759 100644 --- a/app/Services/Model/Imp/SummitOrderService.php +++ b/app/Services/Model/Imp/SummitOrderService.php @@ -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 ); diff --git a/app/Services/Utils/DoctrineTransactionService.php b/app/Services/Utils/DoctrineTransactionService.php index 527a273..f65a5c0 100644 --- a/app/Services/Utils/DoctrineTransactionService.php +++ b/app/Services/Utils/DoctrineTransactionService.php @@ -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; } diff --git a/app/Services/Utils/EloquentTransactionService.php b/app/Services/Utils/EloquentTransactionService.php index 6b509a6..3db29a8 100644 --- a/app/Services/Utils/EloquentTransactionService.php +++ b/app/Services/Utils/EloquentTransactionService.php @@ -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); } diff --git a/tests/OAuth2SummitTicketsApiTest.php b/tests/OAuth2SummitTicketsApiTest.php index d10af78..45401a7 100644 --- a/tests/OAuth2SummitTicketsApiTest.php +++ b/tests/OAuth2SummitTicketsApiTest.php @@ -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 = <<