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