SpecialContributions: Use PoolCounter to limit concurrency
authorBrad Jorsch <bjorsch@wikimedia.org>
Tue, 19 Nov 2019 19:36:35 +0000 (14:36 -0500)
committerReedy <reedy@wikimedia.org>
Thu, 4 Jun 2020 23:27:53 +0000 (23:27 +0000)
Allow using PoolCounter to limit the number of times a user or IP can
concurrently load Special:Contributions.

By default no limitation is applied. Key 'SpecialContributions' in
$wgPoolCounterConf must be set to configure the concurrency.

Bug: T234450
Change-Id: Ie769fa170093bfb6d281c651d3857545d139e009

RELEASE-NOTES-1.34
includes/specials/SpecialContributions.php
languages/i18n/en.json
languages/i18n/qqq.json

index d035653..dcc6a39 100644 (file)
@@ -6,6 +6,8 @@ THIS IS NOT A RELEASE YET
 
 === Changes since MediaWiki 1.34.1 ===
 * The MultiHttpClient code will fallover to non-curl if curl_multi* is blocked.
+* Per-user concurrency in SpecialContributions can now be limited by setting
+  $wgPoolCounterConf['SpecialContributions'] appropriately.
 
 == MediaWiki 1.34.1 ==
 
index 8f92cd5..c39094e 100644 (file)
@@ -239,19 +239,38 @@ class SpecialContributions extends IncludableSpecialPage {
                        } elseif ( !$pager->getNumRows() ) {
                                $out->addWikiMsg( 'nocontribs', $target );
                        } else {
-                               # Show a message about replica DB lag, if applicable
-                               $lag = $pager->getDatabase()->getSessionLagStatus()['lag'];
-                               if ( $lag > 0 ) {
-                                       $out->showLagWarning( $lag );
-                               }
-
-                               $output = $pager->getBody();
-                               if ( !$this->including() ) {
-                                       $output = $pager->getNavigationBar() .
-                                               $output .
-                                               $pager->getNavigationBar();
+                               // @todo We just want a wiki ID here, not a "DB domain", but
+                               // current status of MediaWiki conflates the two. See T235955.
+                               $poolKey = WikiMap::getCurrentWikiDbDomain() . ':SpecialContributions:';
+                               if ( $this->getUser()->isAnon() ) {
+                                       $poolKey .= 'a:' . $this->getUser()->getName();
+                               } else {
+                                       $poolKey .= 'u:' . $this->getUser()->getId();
                                }
-                               $out->addHTML( $output );
+                               $work = new PoolCounterWorkViaCallback( 'SpecialContributions', $poolKey, [
+                                       'doWork' => function () use ( $pager, $out ) {
+                                               # Show a message about replica DB lag, if applicable
+                                               $lag = $pager->getDatabase()->getSessionLagStatus()['lag'];
+                                               if ( $lag > 0 ) {
+                                                       $out->showLagWarning( $lag );
+                                               }
+
+                                               $output = $pager->getBody();
+                                               if ( !$this->including() ) {
+                                                       $output = $pager->getNavigationBar() .
+                                                               $output .
+                                                               $pager->getNavigationBar();
+                                               }
+                                               $out->addHTML( $output );
+                                       },
+                                       'error' => function () use ( $out ) {
+                                               $msg = $this->getUser()->isAnon()
+                                                       ? 'sp-contributions-concurrency-ip'
+                                                       : 'sp-contributions-concurrency-user';
+                                               $out->wrapWikiMsg( "<div class='errorbox'>\n$1\n</div>", $msg );
+                                       }
+                               ] );
+                               $work->execute();
                        }
 
                        $out->preventClickjacking( $pager->getPreventClickjacking() );
index 7c4eeb6..24e00ad 100644 (file)
        "sp-contributions-footer-anon": "-",
        "sp-contributions-footer-anon-range": "-",
        "sp-contributions-outofrange": "Unable to show any results. The requested IP range is larger than the CIDR limit of /$1.",
+       "sp-contributions-concurrency-user": "Sorry, too many requests are being made from your user account. Please try again later.",
+       "sp-contributions-concurrency-ip": "Sorry, too many requests are being made from your IP address. Please try again later.",
        "whatlinkshere": "What links here",
        "whatlinkshere-title": "Pages that link to \"$1\"",
        "whatlinkshere-summary": "",
index d21857c..56c700d 100644 (file)
        "sp-contributions-footer-anon": "{{ignored}}This is the footer for anonymous users on [[Special:Contributions]].",
        "sp-contributions-footer-anon-range": "{{ignored}}This is the footer for IP ranges on [[Special:Contributions]].",
        "sp-contributions-outofrange": "Message shown when a user tries to view contributions of an IP range that's too large. $1 is the numerical limit imposed on the CIDR range.",
+       "sp-contributions-concurrency-user": "Message shown when a logged-in user tries to load [[Special:Contributions]] too many times at once.",
+       "sp-contributions-concurrency-ip": "Message shown when a logged-out user tries to load [[Special:Contributions]] too many times at once.",
        "whatlinkshere": "The text of the link in the toolbox (on the left, below the search menu) going to [[Special:WhatLinksHere]].\n\nSee also:\n* {{msg-mw|Whatlinkshere}}\n* {{msg-mw|Accesskey-t-whatlinkshere}}\n* {{msg-mw|Tooltip-t-whatlinkshere}}",
        "whatlinkshere-title": "Title of the special page [[Special:WhatLinksHere]]. This page appears when you click on the 'What links here' button in the toolbox. $1 is the name of the page concerned.",
        "whatlinkshere-summary": "{{doc-specialpagesummary|whatlinkshere}}",