Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CompleteExternalTranslationMaintenanceScript
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
56
 printSummaryInfo
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3declare( strict_types = 1 );
4
5namespace MediaWiki\Extension\Translate\Synchronization;
6
7use Maintenance;
8use MediaWiki\Extension\Translate\Services;
9use MediaWiki\Logger\LoggerFactory;
10use MediaWiki\MediaWikiServices;
11use MessageIndexRebuildJob;
12use Psr\Log\LoggerInterface;
13
14/**
15 * @author Abijeet Patro
16 * @license GPL-2.0-or-later
17 * @since 2020.06
18 */
19class CompleteExternalTranslationMaintenanceScript extends Maintenance {
20    public function __construct() {
21        parent::__construct();
22        $this->addDescription(
23            'Check and run MessageIndexRebuild and MessageGroupStats update once ' .
24            'MessageUpdateJobs are done. Intended to be run periodically'
25        );
26        $this->requireExtension( 'Translate' );
27    }
28
29    public function execute() {
30        $mwServices = MediaWikiServices::getInstance();
31        $config = $mwServices->getMainConfig();
32
33        if ( !$config->get( 'TranslateGroupSynchronizationCache' ) ) {
34            $this->fatalError( 'GroupSynchronizationCache is not enabled' );
35        }
36
37        $logger = LoggerFactory::getInstance( 'Translate.GroupSynchronization' );
38        $groupSyncCache = Services::getInstance()->getGroupSynchronizationCache();
39        $groupsInSync = $groupSyncCache->getGroupsInSync();
40        if ( !$groupsInSync ) {
41            $logger->debug( 'Nothing to synchronize' );
42            $this->printSummaryInfo( $groupSyncCache, $logger, $groupsInSync );
43            return;
44        }
45
46        $logger->info(
47            'Group synchronization is in progress for {count} groups. Checking latest status...',
48            [ 'count' => count( $groupsInSync ) ]
49        );
50
51        $groupsInProgress = [];
52        foreach ( $groupsInSync as $groupId ) {
53            $groupResponse = $groupSyncCache->getSynchronizationStatus( $groupId );
54
55            if ( $groupResponse->isDone() ) {
56                $groupSyncCache->endSync( $groupId );
57                continue;
58            }
59
60            if ( $groupResponse->hasTimedOut() ) {
61                $remainingMessages = $groupResponse->getRemainingMessages();
62                $logger->warning(
63                    'MessageUpdateJobs timed out for group - {groupId}; ' .
64                    'Messages - {messages}; ' .
65                    'Jobs remaining - {jobRemaining}',
66                    [
67                        'groupId' => $groupId,
68                        'jobRemaining' => count( $remainingMessages ),
69                        'messages' => implode( ', ', array_keys( $remainingMessages ) )
70                    ]
71                );
72
73                $count = count( $remainingMessages );
74                wfLogWarning( "MessageUpdateJob timed out for group $groupId with $count message(s) remaining" );
75                $groupSyncCache->forceEndSync( $groupId );
76
77                $groupSyncCache->addGroupErrors( $groupResponse );
78
79            } else {
80                $groupsInProgress[] = $groupId;
81            }
82        }
83
84        if ( !$groupsInProgress ) {
85            // No groups in progress.
86            $logger->info( 'All message groups are now in sync.' );
87            $mwServices->getJobQueueGroup()->push( MessageIndexRebuildJob::newJob() );
88        }
89
90        $logger->info( "Script completed successfully." );
91        $this->printSummaryInfo( $groupSyncCache, $logger, $groupsInProgress );
92    }
93
94    private function printSummaryInfo(
95        GroupSynchronizationCache $groupSyncCache,
96        LoggerInterface $logger,
97        array $groupsInSync
98    ): void {
99        $summaryMessage = [ 'Current group sync summary:' ];
100        $summaryParams = [];
101
102        $summaryMessage[] = '{syncCount} in sync: {syncGroups}';
103        $summaryParams[ 'syncCount' ] = count( $groupsInSync );
104        $summaryParams[ 'syncGroups' ] = $groupsInSync ? implode( ', ', $groupsInSync ) : 'N/A';
105
106        $groupsInReview = $groupSyncCache->getGroupsInReview();
107        $summaryMessage[] = '{reviewCount} in review: {reviewGroups}';
108        $summaryParams[ 'reviewCount' ] = count( $groupsInReview );
109        $summaryParams[ 'reviewGroups' ] = $groupsInReview ? implode( ', ', $groupsInReview ) : 'N/A';
110
111        $groupsWithError = $groupSyncCache->getGroupsWithErrors();
112        $summaryMessage[] = '{errorCount} with errors: {errorGroups}';
113        $summaryParams[ 'errorCount' ] = count( $groupsWithError );
114        $summaryParams[ 'errorGroups' ] = $groupsWithError ? implode( ', ', $groupsWithError ) : 'N/A';
115
116        $logger->info(
117            implode( '; ', $summaryMessage ),
118            $summaryParams
119        );
120    }
121}