Add action/user tracking to link refresh jobs
authorAaron Schulz <aschulz@wikimedia.org>
Thu, 19 Oct 2017 20:10:14 +0000 (13:10 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Mon, 23 Oct 2017 18:06:16 +0000 (11:06 -0700)
Change-Id: Ie7261eacddb869988b005ba2f17968df88c7003e

includes/api/ApiPurge.php
includes/deferred/DataUpdate.php
includes/deferred/LinksUpdate.php
includes/filerepo/file/LocalFile.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/page/WikiPage.php

index 35f93e0..4b8ce7f 100644 (file)
@@ -93,6 +93,7 @@ class ApiPurge extends ApiBase {
                                                $updates = $content->getSecondaryDataUpdates(
                                                        $title, null, $forceRecursiveLinkUpdate, $p_result );
                                                foreach ( $updates as $update ) {
+                                                       $update->setCause( 'api-purge', $this->getUser()->getName() );
                                                        DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
                                                }
 
index d2d8bd7..ed9a746 100644 (file)
 abstract class DataUpdate implements DeferrableUpdate {
        /** @var mixed Result from LBFactory::getEmptyTransactionTicket() */
        protected $ticket;
+       /** @var string Short update cause action description */
+       protected $causeAction = 'unknown';
+       /** @var string Short update cause user description */
+       protected $causeAgent = 'unknown';
 
        public function __construct() {
                // noop
@@ -41,6 +45,29 @@ abstract class DataUpdate implements DeferrableUpdate {
                $this->ticket = $ticket;
        }
 
+       /**
+        * @param string $action Action type
+        * @param string $user User name
+        */
+       public function setCause( $action, $user ) {
+               $this->causeAction = $action;
+               $this->causeAgent = $user;
+       }
+
+       /**
+        * @return string
+        */
+       public function getCauseAction() {
+               return $this->causeAction;
+       }
+
+       /**
+        * @return string
+        */
+       public function getCauseAgent() {
+               return $this->causeAgent;
+       }
+
        /**
         * Convenience method, calls doUpdate() on every DataUpdate in the array.
         *
index dfe89ba..c27826d 100644 (file)
@@ -306,10 +306,13 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
         * using the job queue.
         */
        protected function queueRecursiveJobs() {
-               self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
+               $action = $this->getCauseAction();
+               $agent = $this->getCauseAgent();
+
+               self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks', $action, $agent );
                if ( $this->mTitle->getNamespace() == NS_FILE ) {
                        // Process imagelinks in case the title is or was a redirect
-                       self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
+                       self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks', $action, $agent );
                }
 
                $bc = $this->mTitle->getBacklinkCache();
@@ -320,7 +323,13 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                // Which ever runs first generally no-ops the other one.
                $jobs = [];
                foreach ( $bc->getCascadeProtectedLinks() as $title ) {
-                       $jobs[] = RefreshLinksJob::newPrioritized( $title, [] );
+                       $jobs[] = RefreshLinksJob::newPrioritized(
+                               $title,
+                               [
+                                       'causeAction' => $action,
+                                       'causeAgent' => $agent
+                               ]
+                       );
                }
                JobQueueGroup::singleton()->push( $jobs );
        }
@@ -330,8 +339,12 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
         *
         * @param Title $title Title to do job for
         * @param string $table Table to use (e.g. 'templatelinks')
+        * @param string $action Triggering action
+        * @param string $userName Triggering user name
         */
-       public static function queueRecursiveJobsForTable( Title $title, $table ) {
+       public static function queueRecursiveJobsForTable(
+               Title $title, $table, $action = 'unknown', $userName = 'unknown'
+       ) {
                if ( $title->getBacklinkCache()->hasLinks( $table ) ) {
                        $job = new RefreshLinksJob(
                                $title,
@@ -340,7 +353,7 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                                        'recursive' => true,
                                ] + Job::newRootJobParams( // "overall" refresh links job info
                                        "refreshlinks:{$table}:{$title->getPrefixedText()}"
-                               )
+                               ) + [ 'causeAction' => $action, 'causeAgent' => $userName ]
                        );
 
                        JobQueueGroup::singleton()->push( $job );
@@ -1156,6 +1169,8 @@ class LinksUpdate extends DataUpdate implements EnqueueableDataUpdate {
                                        'useRecursiveLinksUpdate' => $this->mRecursive,
                                        'triggeringUser' => $userInfo,
                                        'triggeringRevisionId' => $triggeringRevisionId,
+                                       'causeAction' => $this->getCauseAction(),
+                                       'causeAgent' => $this->getCauseAgent()
                                ],
                                [ 'removeDuplicates' => true ],
                                $this->getTitle()
index a36bec3..3271c96 100644 (file)
@@ -1646,7 +1646,12 @@ class LocalFile extends File {
                                                );
                                        } else {
                                                # Update backlink pages pointing to this title if created
-                                               LinksUpdate::queueRecursiveJobsForTable( $this->getTitle(), 'imagelinks' );
+                                               LinksUpdate::queueRecursiveJobsForTable(
+                                                       $this->getTitle(),
+                                                       'imagelinks',
+                                                       'upload-image',
+                                                       $user->getName()
+                                               );
                                        }
 
                                        $this->prerenderThumbnails();
index 51e964d..8854c65 100644 (file)
@@ -53,6 +53,7 @@ class RefreshLinksJob extends Job {
                        // Multiple pages per job make matches unlikely
                        !( isset( $params['pages'] ) && count( $params['pages'] ) != 1 )
                );
+               $this->params += [ 'causeAction' => 'unknown', 'causeAgent' => 'unknown' ];
        }
 
        /**
@@ -102,6 +103,9 @@ class RefreshLinksJob extends Job {
                        // Carry over information for de-duplication
                        $extraParams = $this->getRootJobParams();
                        $extraParams['triggeredRecursive'] = true;
+                       // Carry over cause information for logging
+                       $extraParams['causeAction'] = $this->params['causeAction'];
+                       $extraParams['causeAgent'] = $this->params['causeAgent'];
                        // Convert this into no more than $wgUpdateRowsPerJob RefreshLinks per-title
                        // jobs and possibly a recursive RefreshLinks job for the rest of the backlinks
                        $jobs = BacklinkJobUtils::partitionBacklinkJob(
@@ -254,6 +258,8 @@ class RefreshLinksJob extends Job {
                $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
 
                foreach ( $updates as $update ) {
+                       // Carry over cause in case so the update can do extra logging
+                       $update->setCause( $this->params['causeAction'], $this->params['causeAgent'] );
                        // FIXME: This code probably shouldn't be here?
                        // Needed by things like Echo notifications which need
                        // to know which user caused the links update
@@ -288,6 +294,8 @@ class RefreshLinksJob extends Job {
 
        public function getDeduplicationInfo() {
                $info = parent::getDeduplicationInfo();
+               unset( $info['causeAction'] );
+               unset( $info['causeAgent'] );
                if ( is_array( $info['params'] ) ) {
                        // For per-pages jobs, the job title is that of the template that changed
                        // (or similar), so remove that since it ruins duplicate detection
index d0a04c0..e875df5 100644 (file)
@@ -2171,6 +2171,7 @@ class WikiPage implements Page, IDBAccessObject {
                                $this->getTitle(), null, $recursive, $editInfo->output
                        );
                        foreach ( $updates as $update ) {
+                               $update->setCause( 'edit-page', $user->getName() );
                                if ( $update instanceof LinksUpdate ) {
                                        $update->setRevision( $revision );
                                        $update->setTriggeringUser( $user );
@@ -2913,7 +2914,7 @@ class WikiPage implements Page, IDBAccessObject {
 
                $dbw->endAtomic( __METHOD__ );
 
-               $this->doDeleteUpdates( $id, $content, $revision );
+               $this->doDeleteUpdates( $id, $content, $revision, $user );
 
                Hooks::run( 'ArticleDeleteComplete', [
                        &$wikiPageBeforeDelete,
@@ -2964,8 +2965,11 @@ class WikiPage implements Page, IDBAccessObject {
         *   the required updates. This may be needed because $this->getContent()
         *   may already return null when the page proper was deleted.
         * @param Revision|null $revision The latest page revision
+        * @param User|null $user The user that caused the deletion
         */
-       public function doDeleteUpdates( $id, Content $content = null, Revision $revision = null ) {
+       public function doDeleteUpdates(
+               $id, Content $content = null, Revision $revision = null, User $user = null
+       ) {
                try {
                        $countable = $this->isCountable();
                } catch ( Exception $ex ) {
@@ -2983,12 +2987,14 @@ class WikiPage implements Page, IDBAccessObject {
                        DeferredUpdates::addUpdate( $update );
                }
 
+               $causeAgent = $user ? $user->getName() : 'unknown';
                // Reparse any pages transcluding this page
-               LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
-
+               LinksUpdate::queueRecursiveJobsForTable(
+                       $this->mTitle, 'templatelinks', 'delete-page', $causeAgent );
                // Reparse any pages including this image
                if ( $this->mTitle->getNamespace() == NS_FILE ) {
-                       LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
+                       LinksUpdate::queueRecursiveJobsForTable(
+                               $this->mTitle, 'imagelinks', 'delete-page', $causeAgent );
                }
 
                // Clear caches