From 14e2f8b8e4ac6afae1f20af100538daad2f581b5 Mon Sep 17 00:00:00 2001 From: Andrew Engelbrecht Date: Tue, 3 Jan 2017 16:48:09 -0500 Subject: [PATCH] Updated race cond handling for member badges gen This change removes the universal 0.5 second sleep prior to querying the database about the membership since date. Instead, the process now goes right ahead with the query. It sleeps for 2 seconds if the first query did not succeed, then it re-attempts the query a second time and continues on as before. This should cost less time on average while catching more race conditions with the longer conditional sleep. --- memberdashboard.php | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/memberdashboard.php b/memberdashboard.php index 202b62e..e795746 100644 --- a/memberdashboard.php +++ b/memberdashboard.php @@ -125,22 +125,30 @@ function memberdashboard_civicrm_post($op, $objectName, $objectId, &$objectRef) // TODO: Extract all of this to a class for clarity and // organization's sake. - // sleep for a half second in order to avoid a race condition preventing badge creation. - // This is somewhat sketchy, as this will tie up an apache processes, allowing for a DoS by someone - // creating many phony memberships in a short period of time. - // In practice, this isn't so bad. apache is currently configured to use prefork mpm on crmserver1p - // and has about 40 forked processes. so 800 new memberships all at once would tie up the server for - // an additional 10 seconds. - usleep(500000); - // Get the oldest join date for the contact's memberships. - $contactId = $objectRef->contact_id; - $dao = CRM_Core_DAO::executeQuery( - 'SELECT join_date FROM civicrm_membership WHERE contact_id=%1 ORDER BY join_date ASC LIMIT 1', - array( 1 => array($contactId, 'Integer') ) - ); + $getDao = function () { + + $contactId = $objectRef->contact_id; + $dao = CRM_Core_DAO::executeQuery( + 'SELECT join_date FROM civicrm_membership WHERE contact_id=%1 ORDER BY join_date ASC LIMIT 1', + array( 1 => array($contactId, 'Integer') ) + ); + return $dao; + }; + + $dao = $getDao(); + $fetchResult = $dao->fetch(); + + if(!$fetchResult) { + // retry after sleeping 2 seconds in order to avoid a race condition + usleep(2000000); + $dao->free(); + + $dao = $getDao(); + $fetchResult = $dao->fetch(); + } - if($dao->fetch()) { + if($fetchResult) { // Make the API call. $joinDate = $dao->join_date; $apiUrl = civicrm_api3('setting', 'getvalue', array( -- 2.25.1