Awight has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/233877

Change subject: Clean up orphan classes
......................................................................

Clean up orphan classes

Move classes into own files and out of maintenance scripts dir.

Change-Id: I67751d4c325cc9e52a9a0e23770451fcbb110a7e
---
M DonationInterface.php
A globalcollect_gateway/GlobalCollectOrphanRectifier.php
R globalcollect_gateway/orphan.adapter.php
M globalcollect_gateway/scripts/orphans.php
4 files changed, 243 insertions(+), 237 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DonationInterface 
refs/changes/77/233877/1

diff --git a/DonationInterface.php b/DonationInterface.php
index 388c2d5..920b2f0 100644
--- a/DonationInterface.php
+++ b/DonationInterface.php
@@ -74,8 +74,8 @@
 $wgAutoloadClasses['GlobalCollectGatewayResult'] = __DIR__ . 
'/globalcollect_gateway/globalcollect_resultswitcher.body.php';
 
 $wgAutoloadClasses['GlobalCollectAdapter'] = __DIR__ . 
'/globalcollect_gateway/globalcollect.adapter.php';
-$wgAutoloadClasses['GlobalCollectOrphanAdapter'] = __DIR__ . 
'/globalcollect_gateway/scripts/orphan.adapter.php';
-$wgAutoloadClasses['GlobalCollectOrphanRectifier'] = __DIR__ . 
'/globalcollect_gateway/scripts/orphans.php';
+$wgAutoloadClasses['GlobalCollectOrphanAdapter'] = __DIR__ . 
'/globalcollect_gateway/orphan.adapter.php';
+$wgAutoloadClasses['GlobalCollectOrphanRectifier'] = __DIR__ . 
'/globalcollect_gateway/GlobalCollectOrphanRectifier.php';
 
 // Amazon
 $wgAutoloadClasses['AmazonGateway'] = __DIR__ . 
'/amazon_gateway/amazon_gateway.body.php';
diff --git a/globalcollect_gateway/GlobalCollectOrphanRectifier.php 
b/globalcollect_gateway/GlobalCollectOrphanRectifier.php
new file mode 100644
index 0000000..e597ed1
--- /dev/null
+++ b/globalcollect_gateway/GlobalCollectOrphanRectifier.php
@@ -0,0 +1,226 @@
+<?php
+/**
+ * TODO: Generalize to all gateways, using hooks to implement polymorphism.
+ */
+
+use Predis\Connection\ConnectionException;
+
+class GlobalCollectOrphanRectifier {
+
+       protected $killfiles = array();
+       protected $order_ids = array();
+       protected $target_execute_time;
+       protected $max_per_execute; //only really used if you're going by-file.
+       protected $adapter;
+
+       public function __construct() {
+               // Have to turn this off here, until we know it's using the 
user's ip, and
+               // not 127.0.0.1 during the batch process.  Otherwise, we'll 
immediately
+               // lock ourselves out when processing multiple charges.
+               global $wgDonationInterfaceEnableIPVelocityFilter;
+               $wgDonationInterfaceEnableIPVelocityFilter = false;
+
+               if ( !$this->getOrphanGlobal( 'enable' ) ){
+                       $this->info( 'Orphan cron disabled. Have a nice day!' );
+                       return;
+               }
+
+               $this->target_execute_time = $this->getOrphanGlobal( 
'target_execute_time' );
+               $this->max_per_execute = $this->getOrphanGlobal( 
'max_per_execute' );
+
+               // FIXME: Is this just to trigger batch mode?
+               $data = array(
+                       'wheeee' => 'yes'
+               );
+               $this->adapter = new 
GlobalCollectOrphanAdapter(array('external_data' => $data));
+               $this->logger = DonationLoggerFactory::getLogger( 
$this->adapter );
+       }
+
+       protected function keepGoing(){
+               $elapsed = $this->getProcessElapsed();
+               if ( $elapsed < $this->target_execute_time ) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * This will both return the elapsed process time, and echo something 
for
+        * the cronspammer.
+        * @return int elapsed time since start in seconds
+        */
+       protected function getProcessElapsed(){
+               $elapsed = time() - $this->start_time;
+               $this->info( "Elapsed Time: {$elapsed}" );
+               return $elapsed;
+       }
+
+       protected function deleteMessage( $correlation_id, $queue ) {
+           DonationQueue::instance()->delete( $correlation_id, $queue );
+       }
+
+       protected function processOrphans() {
+               // TODO: Make this configurable.
+               // 20 minutes: this is exactly equal to something on 
Globalcollect's side.
+               $time_buffer = 60*20;
+
+               $queue_pool = new CyclicalArray( $this->getOrphanGlobal( 
'gc_cc_limbo_queue_pool' ) );
+               if ( $queue_pool->isEmpty() ) {
+                       // FIXME: cheesy inline default
+                       $queue_pool = new CyclicalArray( 
GlobalCollectAdapter::GC_CC_LIMBO_QUEUE );
+               }
+
+               $this->info( "Slaying orphans..." );
+               $this->start_time = time();
+
+               //I want to be clear on the problem I hope to prevent with 
this.  Say,
+               //for instance, we pull a legit orphan, and for whatever 
reason, can't
+               //completely rectify it.  Then, we go back and pull more... and 
that
+               //same one is in the list again. We should stop after one try 
per
+               //message per execute.  We should also be smart enough to not 
process
+               //things we believe we just deleted.
+               $this->handled_ids = array();
+
+               while ( $this->keepGoing() && !$queue_pool->isEmpty() ) {
+                       $current_queue = $queue_pool->current();
+                       try {
+                               $message = DonationQueue::instance()->peek( 
$current_queue );
+
+                               if ( !$message ) {
+                                       $this->info( "Emptied queue 
[{$current_queue}], removing from pool." );
+                                       $queue_pool->dropCurrent();
+                                       continue;
+                               }
+
+                               $correlation_id = 'globalcollect-' . 
$message['gateway_txn_id'];
+                               if ( array_key_exists( $correlation_id, 
$this->handled_ids ) ) {
+                                       // We already did this one, keep going. 
 It's fine to draw
+                                       // again from the same queue.
+                                       DonationQueue::instance()->delete( 
$correlation_id, $current_queue );
+                                       continue;
+                               }
+
+                               // Check the timestamp to see if it's old 
enough, and stop when
+                               // we're below the threshold.  Messages are 
guaranteed to pop in
+                               // chronological order.
+                               $elapsed = $this->start_time - $message['date'];
+                               if ( $elapsed < $time_buffer ) {
+                                       $this->info( "Exhausted new messages in 
[{$current_queue}], removing from pool..." );
+                                       $queue_pool->dropCurrent();
+
+                                       continue;
+                               }
+
+                               // We got ourselves an orphan!
+                               if ( $this->rectifyOrphan( $message ) ) {
+                                       $this->handled_ids[$correlation_id] = 
'rectified';
+                               } else {
+                                       $this->handled_ids[$correlation_id] = 
'error';
+                               }
+
+                               // Throw out the message either way.
+                               $this->deleteMessage( $correlation_id, 
$current_queue );
+
+                               // Round-robin the pool before we complete the 
loop.
+                               $queue_pool->rotate();
+                       } catch ( ConnectionException $ex ) {
+                               // Drop this server, for the duration of this 
batch.
+                               $this->error( "Queue server for 
[$current_queue] is down! Ignoring for this run..." );
+                               $queue_pool->dropCurrent();
+                       }
+               }
+
+               //TODO: Make stats squirt out all over the place.
+               $rec = 0;
+               $err = 0;
+               foreach( $this->handled_ids as $id=>$whathappened ){
+                       switch ( $whathappened ){
+                               case 'rectified':
+                                       $rec += 1;
+                                       break;
+                               case 'error':
+                                       $err += 1;
+                                       break;
+                       }
+               }
+               $final = "\nDone! Final results: \n";
+               $final .= " $rec rectified orphans \n";
+               $final .= " $err errored out \n";
+               if ( isset( $this->adapter->orphanstats ) ){
+                       foreach ( $this->adapter->orphanstats as $status => 
$count ) {
+                               $final .= "\n   Status $status = $count";
+                       }
+               }
+               $final .= "\n Approximately " . $this->getProcessElapsed() . " 
seconds to execute.\n";
+               $this->info( $final );
+       }
+
+       /**
+        * Uses the Orphan Adapter to rectify (complete the charge for) a 
single orphan. Returns a boolean letting the caller know if
+        * the orphan has been fully rectified or not.
+        * @param array $data Some set of orphan data.
+        * @param boolean $query_contribution_tracking A flag specifying if we 
should query the contribution_tracking table or not.
+        * @return boolean True if the orphan has been rectified, false if not.
+        */
+       protected function rectifyOrphan( $data, $query_contribution_tracking = 
true ){
+               $data['order_id'] = $data['gateway_txn_id'];
+
+               $this->info( "Rectifying orphan: {$data['order_id']}" );
+               $rectified = false;
+
+               $normalized = DonationQueue::queueMessageToNormalized( $data );
+               $this->adapter->loadDataAndReInit( $normalized, 
$query_contribution_tracking );
+               $results = $this->adapter->do_transaction( 'Confirm_CreditCard' 
);
+               $message = $results->getMessage();
+               if ( $results->getCommunicationStatus() ){
+                       $this->info( $data['contribution_tracking_id'] . ": 
FINAL: " . $this->adapter->getValidationAction() );
+                       $rectified = true;
+               } else {
+                       $this->info( $data['contribution_tracking_id'] . ": 
ERROR: " . $message );
+                       if ( strpos( $message, "GET_ORDERSTATUS reports that 
the payment is already complete." ) === 0  ){
+                               $rectified = true;
+                       }
+
+                       //handles the transactions we've cancelled ourselves... 
though if they got this far, that's a problem too.
+                       $errors = $results->getErrors();
+                       if ( !empty( $errors ) && array_key_exists( '1000001', 
$errors ) ){
+                               $rectified = true;
+                       }
+
+                       //apparently this is well-formed GlobalCollect for 
"iono". Get rid of it.
+                       if ( strpos( $message, "No processors are available." ) 
=== 0 ){
+                               $rectified = true;
+                       }
+               }
+
+               $this->info( $message );
+
+               return $rectified;
+       }
+
+       /**
+        * Gets the global setting for the key passed in.
+        * @param type $key
+        *
+        * FIXME: Reuse GatewayAdapter::getGlobal.
+        */
+       protected static function getOrphanGlobal( $key ){
+               global $wgDonationInterfaceOrphanCron;
+               if ( array_key_exists( $key, $wgDonationInterfaceOrphanCron ) ){
+                       return $wgDonationInterfaceOrphanCron[$key];
+               } else {
+                       return NULL;
+               }
+       }
+
+       protected function info( $msg ) {
+               $this->logger->info( $msg );
+               print( "{$msg}\n" );
+       }
+
+       protected function error( $msg ) {
+               $this->logger->error( $msg );
+               error_log( $msg );
+       }
+}
diff --git a/globalcollect_gateway/scripts/orphan.adapter.php 
b/globalcollect_gateway/orphan.adapter.php
similarity index 95%
rename from globalcollect_gateway/scripts/orphan.adapter.php
rename to globalcollect_gateway/orphan.adapter.php
index ef11f2a..91b99d4 100644
--- a/globalcollect_gateway/scripts/orphan.adapter.php
+++ b/globalcollect_gateway/orphan.adapter.php
@@ -1,8 +1,8 @@
 <?php
 
 class GlobalCollectOrphanAdapter extends GlobalCollectAdapter {
-       //Data we know to be good, that we always want to re-assert after a 
load or an addData. 
-       //so far: order_id and the utm data we pull from contribution tracking. 
+       //Data we know to be good, that we always want to re-assert after a 
load or an addData.
+       //so far: order_id and the utm data we pull from contribution tracking.
        protected $hard_data = array ( );
 
        public static function getLogIdentifier() {
@@ -22,9 +22,9 @@
                                $unstaged += $this->unstage_data( $val, false );
                        } else {
                                if ( array_key_exists( $key, $this->var_map ) ) 
{
-                                       //run the unstage data functions. 
+                                       //run the unstage data functions.
                                        $unstaged[$this->var_map[$key]] = $val;
-                                       //this would be EXTREMELY bad to put in 
the regular adapter. 
+                                       //this would be EXTREMELY bad to put in 
the regular adapter.
                                        
$this->staged_data[$this->var_map[$key]] = $val;
                                } else {
                                        //$unstaged[$key] = $val;
@@ -67,7 +67,7 @@
                        );
                        foreach($utm_keys as $key){
                                $this->hard_data[$key] = $data[$key];
-                       }                       
+                       }
                }
                $this->reAddHardData();
 
@@ -81,9 +81,9 @@
 
                $this->stageData();
 
-               //have to do this again here. 
+               //have to do this again here.
                $this->reAddHardData();
-               
+
                $this->revalidate();
        }
 
@@ -94,7 +94,7 @@
 
        private function reAddHardData() {
                //anywhere else, and this would constitute abuse of the system.
-               //so don't do it. 
+               //so don't do it.
                $data = $this->hard_data;
 
                if ( array_key_exists( 'order_id', $data ) ) {
@@ -117,16 +117,16 @@
 
                $data = array( );
 
-               // if contrib tracking id is not already set, we need to insert 
the data, otherwise update                      
+               // if contrib tracking id is not already set, we need to insert 
the data, otherwise update
                if ( $ctid ) {
                        $res = $db->select(
-                               'contribution_tracking', 
+                               'contribution_tracking',
                                array(
                                        'utm_source',
                                        'utm_campaign',
                                        'utm_medium',
                                        'ts'
-                               ), 
+                               ),
                                array( 'id' => $ctid )
                        );
                        foreach ( $res as $thing ) {
diff --git a/globalcollect_gateway/scripts/orphans.php 
b/globalcollect_gateway/scripts/orphans.php
index 451df9b..b8c65d4 100644
--- a/globalcollect_gateway/scripts/orphans.php
+++ b/globalcollect_gateway/scripts/orphans.php
@@ -10,230 +10,10 @@
 //If you get errors on this next line, set (and export) your MW_INSTALL_PATH 
var. 
 require_once( "$IP/maintenance/Maintenance.php" );
 
-use Predis\Connection\ConnectionException;
-
-class GlobalCollectOrphanRectifier extends Maintenance {
-
-       protected $killfiles = array();
-       protected $order_ids = array();
-       protected $target_execute_time;
-       protected $max_per_execute; //only really used if you're going by-file.
-       protected $adapter;
-
-       public function execute() {
-               // Have to turn this off here, until we know it's using the 
user's ip, and
-               // not 127.0.0.1 during the batch process.  Otherwise, we'll 
immediately
-               // lock ourselves out when processing multiple charges.
-               global $wgDonationInterfaceEnableIPVelocityFilter;
-               $wgDonationInterfaceEnableIPVelocityFilter = false;
-
-               if ( !$this->getOrphanGlobal( 'enable' ) ){
-                       $this->info( 'Orphan cron disabled. Have a nice day!' );
-                       return;
-               }
-
-               $this->target_execute_time = $this->getOrphanGlobal( 
'target_execute_time' );
-               $this->max_per_execute = $this->getOrphanGlobal( 
'max_per_execute' );
-
-               // FIXME: Is this just to trigger batch mode?
-               $data = array(
-                       'wheeee' => 'yes'
-               );
-               $this->adapter = new 
GlobalCollectOrphanAdapter(array('external_data' => $data));
-               $this->logger = DonationLoggerFactory::getLogger( 
$this->adapter );
-
-               //Now, actually do the processing. 
-               $this->processOrphans();
-       }
-
-       protected function keepGoing(){
-               $elapsed = $this->getProcessElapsed();
-               if ( $elapsed < $this->target_execute_time ) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * This will both return the elapsed process time, and echo something 
for 
-        * the cronspammer.
-        * @return int elapsed time since start in seconds
-        */
-       protected function getProcessElapsed(){
-               $elapsed = time() - $this->start_time;
-               $this->info( "Elapsed Time: {$elapsed}" );
-               return $elapsed;
-       }
-
-       protected function deleteMessage( $correlation_id, $queue ) {
-           DonationQueue::instance()->delete( $correlation_id, $queue );
-       }
-
-       protected function processOrphans() {
-               // TODO: Make this configurable.
-               // 20 minutes: this is exactly equal to something on 
Globalcollect's side.
-               $time_buffer = 60*20;
-
-               $queue_pool = new CyclicalArray( $this->getOrphanGlobal( 
'gc_cc_limbo_queue_pool' ) );
-               if ( $queue_pool->isEmpty() ) {
-                       // FIXME: cheesy inline default
-                       $queue_pool = new CyclicalArray( 
GlobalCollectAdapter::GC_CC_LIMBO_QUEUE );
-               }
-
-               $this->info( "Slaying orphans..." );
-               $this->start_time = time();
-
-               //I want to be clear on the problem I hope to prevent with 
this.  Say,
-               //for instance, we pull a legit orphan, and for whatever 
reason, can't
-               //completely rectify it.  Then, we go back and pull more... and 
that
-               //same one is in the list again. We should stop after one try 
per
-               //message per execute.  We should also be smart enough to not 
process
-               //things we believe we just deleted.
-               $this->handled_ids = array();
-
-               while ( $this->keepGoing() && !$queue_pool->isEmpty() ) {
-                       $current_queue = $queue_pool->current();
-                       try {
-                               $message = DonationQueue::instance()->peek( 
$current_queue );
-
-                               if ( !$message ) {
-                                       $this->info( "Emptied queue 
[{$current_queue}], removing from pool." );
-                                       $queue_pool->dropCurrent();
-                                       continue;
-                               }
-
-                               $correlation_id = 'globalcollect-' . 
$message['gateway_txn_id'];
-                               if ( array_key_exists( $correlation_id, 
$this->handled_ids ) ) {
-                                       // We already did this one, keep going. 
 It's fine to draw
-                                       // again from the same queue.
-                                       DonationQueue::instance()->delete( 
$correlation_id, $current_queue );
-                                       continue;
-                               }
-
-                               // Check the timestamp to see if it's old 
enough, and stop when
-                               // we're below the threshold.  Messages are 
guaranteed to pop in
-                               // chronological order.
-                               $elapsed = $this->start_time - $message['date'];
-                               if ( $elapsed < $time_buffer ) {
-                                       $this->info( "Exhausted new messages in 
[{$current_queue}], removing from pool..." );
-                                       $queue_pool->dropCurrent();
-
-                                       continue;
-                               }
-
-                               // We got ourselves an orphan!
-                               if ( $this->rectifyOrphan( $message ) ) {
-                                       $this->handled_ids[$correlation_id] = 
'rectified';
-                               } else {
-                                       $this->handled_ids[$correlation_id] = 
'error';
-                               }
-
-                               // Throw out the message either way.
-                               $this->deleteMessage( $correlation_id, 
$current_queue );
-
-                               // Round-robin the pool before we complete the 
loop.
-                               $queue_pool->rotate();
-                       } catch ( ConnectionException $ex ) {
-                               // Drop this server, for the duration of this 
batch.
-                               $this->error( "Queue server for 
[$current_queue] is down! Ignoring for this run..." );
-                               $queue_pool->dropCurrent();
-                       }
-               }
-
-               //TODO: Make stats squirt out all over the place.  
-               $rec = 0;
-               $err = 0;
-               foreach( $this->handled_ids as $id=>$whathappened ){
-                       switch ( $whathappened ){
-                               case 'rectified' : 
-                                       $rec += 1;
-                                       break;
-                               case 'error' :
-                                       $err += 1;
-                                       break;
-                       }
-               }
-               $final = "\nDone! Final results: \n";
-               $final .= " $rec rectified orphans \n";
-               $final .= " $err errored out \n";
-               if ( isset( $this->adapter->orphanstats ) ){
-                       foreach ( $this->adapter->orphanstats as $status => 
$count ) {
-                               $final .= "\n   Status $status = $count";
-                       }
-               }
-               $final .= "\n Approximately " . $this->getProcessElapsed() . " 
seconds to execute.\n";
-               $this->info( $final );
-       }
-
-       /**
-        * Uses the Orphan Adapter to rectify (complete the charge for) a 
single orphan. Returns a boolean letting the caller know if
-        * the orphan has been fully rectified or not. 
-        * @param array $data Some set of orphan data. 
-        * @param boolean $query_contribution_tracking A flag specifying if we 
should query the contribution_tracking table or not.
-        * @return boolean True if the orphan has been rectified, false if not. 
-        */
-       protected function rectifyOrphan( $data, $query_contribution_tracking = 
true ){
-               $data['order_id'] = $data['gateway_txn_id'];
-
-               $this->info( "Rectifying orphan: {$data['order_id']}" );
-               $rectified = false;
-
-               $normalized = DonationQueue::queueMessageToNormalized( $data );
-               $this->adapter->loadDataAndReInit( $normalized, 
$query_contribution_tracking );
-               $results = $this->adapter->do_transaction( 'Confirm_CreditCard' 
);
-               $message = $results->getMessage();
-               if ( $results->getCommunicationStatus() ){
-                       $this->info( $data['contribution_tracking_id'] . ": 
FINAL: " . $this->adapter->getValidationAction() );
-                       $rectified = true;
-               } else {
-                       $this->info( $data['contribution_tracking_id'] . ": 
ERROR: " . $message );
-                       if ( strpos( $message, "GET_ORDERSTATUS reports that 
the payment is already complete." ) === 0  ){
-                               $rectified = true;
-                       }
-
-                       //handles the transactions we've cancelled ourselves... 
though if they got this far, that's a problem too. 
-                       $errors = $results->getErrors();
-                       if ( !empty( $errors ) && array_key_exists( '1000001', 
$errors ) ){
-                               $rectified = true;
-                       }
-
-                       //apparently this is well-formed GlobalCollect for 
"iono". Get rid of it.
-                       if ( strpos( $message, "No processors are available." ) 
=== 0 ){
-                               $rectified = true;
-                       }
-               }
-
-               $this->info( $message );
-               
-               return $rectified;
-       }
-
-       /**
-        * Gets the global setting for the key passed in.
-        * @param type $key
-        *
-        * FIXME: Reuse GatewayAdapter::getGlobal.
-        */
-       protected function getOrphanGlobal( $key ){
-               global $wgDonationInterfaceOrphanCron;
-               if ( array_key_exists( $key, $wgDonationInterfaceOrphanCron ) ){
-                       return $wgDonationInterfaceOrphanCron[$key];
-               } else {
-                       return NULL;
-               }
-       }
-
-       protected function info( $msg ) {
-               $this->logger->info( $msg );
-               print( "{$msg}\n" );
-       }
-
-       protected function error( $msg ) {
-               $this->logger->error( $msg );
-               error_log( $msg );
-       }
+class OrphanMaintenance extends Maintenance {
+       $rectifier = new GlobalCollectOrphanRectifier();
+       $rectifier->processOrphans();
 }
 
-$maintClass = 'GlobalCollectOrphanRectifier';
+$maintClass = 'OrphanMaintenance';
 require_once RUN_MAINTENANCE_IF_MAIN;

-- 
To view, visit https://gerrit.wikimedia.org/r/233877
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I67751d4c325cc9e52a9a0e23770451fcbb110a7e
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DonationInterface
Gerrit-Branch: master
Gerrit-Owner: Awight <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to