Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
CopyJobQueue
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
3 / 3
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
5
 copyJobs
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3 * Copy all jobs from one job queue system to another.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @ingroup Maintenance
8 */
9
10use MediaWiki\JobQueue\JobQueue;
11use MediaWiki\Maintenance\Maintenance;
12use MediaWiki\WikiMap\WikiMap;
13
14// @codeCoverageIgnoreStart
15require_once __DIR__ . '/Maintenance.php';
16// @codeCoverageIgnoreEnd
17
18/**
19 * Copy all jobs from one job queue system to another.
20 * This uses an ad-hoc $wgJobQueueMigrationConfig setting,
21 * which is a map of queue system names to JobQueue::factory() parameters.
22 * The parameters should not have wiki or type settings and thus partial.
23 *
24 * @ingroup Maintenance
25 */
26class CopyJobQueue extends Maintenance {
27    public function __construct() {
28        parent::__construct();
29        $this->addDescription( 'Copy jobs from one queue system to another.' );
30        $this->addOption( 'src', 'Key to $wgJobQueueMigrationConfig for source', true, true );
31        $this->addOption( 'dst', 'Key to $wgJobQueueMigrationConfig for destination', true, true );
32        $this->addOption( 'type', 'Types of jobs to copy (use "all" for all)', true, true );
33        $this->setBatchSize( 500 );
34    }
35
36    public function execute() {
37        global $wgJobQueueMigrationConfig;
38
39        $srcKey = $this->getOption( 'src' );
40        $dstKey = $this->getOption( 'dst' );
41
42        if ( !isset( $wgJobQueueMigrationConfig[$srcKey] ) ) {
43            $this->fatalError( "\$wgJobQueueMigrationConfig not set for '$srcKey'." );
44        } elseif ( !isset( $wgJobQueueMigrationConfig[$dstKey] ) ) {
45            $this->fatalError( "\$wgJobQueueMigrationConfig not set for '$dstKey'." );
46        }
47
48        $types = ( $this->getOption( 'type' ) === 'all' )
49            ? $this->getServiceContainer()->getJobQueueGroup()->getQueueTypes()
50            : [ $this->getOption( 'type' ) ];
51
52        $dbDomain = WikiMap::getCurrentWikiDbDomain()->getId();
53        foreach ( $types as $type ) {
54            $baseConfig = [ 'type' => $type, 'domain' => $dbDomain ];
55            $src = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$srcKey] );
56            $dst = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$dstKey] );
57
58            [ $total, $totalOK ] = $this->copyJobs( $src, $dst, $src->getAllQueuedJobs() );
59            $this->output( "Copied $totalOK/$total queued $type jobs.\n" );
60
61            [ $total, $totalOK ] = $this->copyJobs( $src, $dst, $src->getAllDelayedJobs() );
62            $this->output( "Copied $totalOK/$total delayed $type jobs.\n" );
63        }
64    }
65
66    protected function copyJobs( JobQueue $src, JobQueue $dst, iterable $jobs ): array {
67        $total = 0;
68        $totalOK = 0;
69        $batch = [];
70        foreach ( $jobs as $job ) {
71            ++$total;
72            $batch[] = $job;
73            if ( count( $batch ) >= $this->getBatchSize() ) {
74                $dst->push( $batch );
75                $totalOK += count( $batch );
76                $batch = [];
77                $dst->waitForBackups();
78            }
79        }
80        if ( count( $batch ) ) {
81            $dst->push( $batch );
82            $totalOK += count( $batch );
83            $dst->waitForBackups();
84        }
85
86        return [ $total, $totalOK ];
87    }
88}
89
90// @codeCoverageIgnoreStart
91$maintClass = CopyJobQueue::class;
92require_once RUN_MAINTENANCE_IF_MAIN;
93// @codeCoverageIgnoreEnd