Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
PurgeExpiredMentorStatus
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 6
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 initServices
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getRows
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 filterAndBatch
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
 execute
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 deleteTimestamps
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace GrowthExperiments\Maintenance;
4
5use GrowthExperiments\MentorDashboard\MentorTools\MentorStatusManager;
6use Maintenance;
7use Wikimedia\Rdbms\IDatabase;
8use Wikimedia\Rdbms\IReadableDatabase;
9use Wikimedia\Timestamp\ConvertibleTimestamp;
10
11$IP = getenv( 'MW_INSTALL_PATH' );
12if ( $IP === false ) {
13    $IP = __DIR__ . '/../../..';
14}
15require_once "$IP/maintenance/Maintenance.php";
16
17/**
18 * Purge expired rows related to mentor status from user_properties
19 */
20class PurgeExpiredMentorStatus extends Maintenance {
21
22    /** @var IReadableDatabase */
23    private $dbr;
24
25    /** @var IDatabase */
26    private $dbw;
27
28    public function __construct() {
29        parent::__construct();
30        $this->requireExtension( 'GrowthExperiments' );
31        $this->addDescription(
32            'Remove expired values of MentorStatusManager::MENTOR_AWAY_TIMESTAMP_PREF from user_properties'
33        );
34        $this->addOption( 'dry-run', 'Do not actually change anything.' );
35        $this->setBatchSize( 100 );
36    }
37
38    private function initServices(): void {
39        $this->dbr = $this->getDB( DB_REPLICA );
40        $this->dbw = $this->getDB( DB_PRIMARY );
41    }
42
43    private function getRows() {
44        yield from $this->dbr->newSelectQueryBuilder()
45            ->select( [ 'up_user', 'up_value' ] )
46            ->from( 'user_properties' )
47            ->where( [ 'up_property' => MentorStatusManager::MENTOR_AWAY_TIMESTAMP_PREF ] )
48            ->caller( __METHOD__ )->fetchResultSet();
49    }
50
51    private function filterAndBatch() {
52        $batch = [];
53        foreach ( $this->getRows() as $row ) {
54            if (
55                $row->up_value === null ||
56                ConvertibleTimestamp::convert( TS_UNIX, $row->up_value ) < wfTimestamp( TS_UNIX )
57            ) {
58                $batch[] = $row->up_user;
59
60                if ( count( $batch ) >= $this->getBatchSize() ) {
61                    yield $batch;
62                    $batch = [];
63                }
64            }
65        }
66
67        if ( $batch !== [] ) {
68            yield $batch;
69        }
70    }
71
72    /**
73     * @inheritDoc
74     */
75    public function execute() {
76        $this->initServices();
77
78        $deletedCount = 0;
79        foreach ( $this->filterAndBatch() as $batch ) {
80            $this->deleteTimestamps( $batch );
81            $deletedCount += count( $batch );
82        }
83
84        if ( $this->getOption( 'dry-run' ) ) {
85            $this->output( "Would delete $deletedCount rows from user_properties.\n" );
86        } else {
87            $this->output( "Deleted $deletedCount rows from user_properties.\n" );
88        }
89    }
90
91    private function deleteTimestamps( array $toDelete ): void {
92        if ( $this->getOption( 'dry-run' ) ) {
93            return;
94        }
95        $this->dbw->begin( __METHOD__ );
96        $this->dbw->newDeleteQueryBuilder()
97            ->deleteFrom( 'user_properties' )
98            ->where( [
99                'up_property' => MentorStatusManager::MENTOR_AWAY_TIMESTAMP_PREF,
100                'up_user' => $toDelete
101            ] )
102            ->caller( __METHOD__ )
103            ->execute();
104        $this->dbw->commit( __METHOD__ );
105        $this->waitForReplication();
106    }
107}
108
109$maintClass = PurgeExpiredMentorStatus::class;
110require_once RUN_MAINTENANCE_IF_MAIN;