Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
65.22% |
30 / 46 |
|
25.00% |
1 / 4 |
CRAP | |
0.00% |
0 / 1 |
FlushUtterancesFromStoreByExpirationJobQueue | |
65.22% |
30 / 46 |
|
25.00% |
1 / 4 |
10.69 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
1 | |||
maybeQueueJob | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
queueJob | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
isTimeToQueueJob | |
81.82% |
18 / 22 |
|
0.00% |
0 / 1 |
4.10 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Wikispeech\Utterance; |
4 | |
5 | /** |
6 | * @file |
7 | * @ingroup Extensions |
8 | * @license GPL-2.0-or-later |
9 | */ |
10 | |
11 | use DateTime; |
12 | use MediaWiki\Logger\LoggerFactory; |
13 | use MediaWiki\MediaWikiServices; |
14 | use Psr\Log\LoggerInterface; |
15 | use Title; |
16 | use WANObjectCache; |
17 | |
18 | /** |
19 | * Periodically flushes out old utterances from the utterance store. |
20 | * |
21 | * This is an important part of the extension architecture, making sure |
22 | * that utterance audio files and synthesis metadata files are updated |
23 | * when underlying voice synthesis is improved. |
24 | * |
25 | * The job is currently queued at the same time as utterances are created, |
26 | * with a configurable minimum amount of minutes delay between queues by |
27 | * executing {@link FlushUtterancesFromStoreByExpirationJob::maybeQueueJob()}. |
28 | * |
29 | * This is more or less equivalent to a semi dysfunctional cron tab. It might |
30 | * make sense to consider implement queuing the job periodically using a real |
31 | * cron tab, but that would also require more manual non standard work when |
32 | * setting up Wikispeech. It might also cause problems with future upgrades. |
33 | * |
34 | * One downside to the current approach is, that in a highly distributed |
35 | * environment with many active users there might be multiple jobs queued |
36 | * before the WAN cache is synchronized. Executing this job multiple times |
37 | * is however not a problem in it self more than being a bit of waste of |
38 | * resources. In the case where Wikispeech is configured to only flush a |
39 | * limited batch of utterances in each job, it might actually be a good |
40 | * thing that multiple jobs are queued. |
41 | * |
42 | * @see UtteranceStore::flushUtterancesByExpirationDate() |
43 | * @see FlushUtterancesFromStoreByExpirationJob |
44 | * |
45 | * @since 0.1.7 |
46 | */ |
47 | class FlushUtterancesFromStoreByExpirationJobQueue { |
48 | |
49 | /** @var LoggerInterface */ |
50 | private $logger; |
51 | |
52 | /** @var WANObjectCache */ |
53 | private $cache; |
54 | |
55 | /** @var string */ |
56 | private $cacheKey; |
57 | |
58 | /** @var string WAN cache key class namespace */ |
59 | public static $cacheKeyClass = 'Wikispeech.flushUtterancesFromStoreByExpirationJob'; |
60 | |
61 | /** @var string WAN cache key component used by pseudo-crontab */ |
62 | public static $cacheKeyComponentPreviousDateTimeQueued = 'previousDateTimeQueued'; |
63 | |
64 | /** @var int */ |
65 | private $minimumMinutesBetweenFlushExpiredUtterancesJobs; |
66 | |
67 | /** |
68 | * @since 0.1.7 |
69 | */ |
70 | public function __construct() { |
71 | $this->logger = LoggerFactory::getInstance( 'Wikispeech' ); |
72 | $config = MediaWikiServices::getInstance() |
73 | ->getConfigFactory() |
74 | ->makeConfig( 'wikispeech' ); |
75 | $this->minimumMinutesBetweenFlushExpiredUtterancesJobs = intval( |
76 | $config->get( 'WikispeechMinimumMinutesBetweenFlushExpiredUtterancesJobs' ) |
77 | ); |
78 | $this->cache = MediaWikiServices::getInstance()->getMainWANObjectCache(); |
79 | $this->cacheKey = $this->cache->makeKey( |
80 | self::$cacheKeyClass, |
81 | self::$cacheKeyComponentPreviousDateTimeQueued |
82 | ); |
83 | } |
84 | |
85 | /** |
86 | * Queues a job if criteria to do so has been met. |
87 | * |
88 | * Convenience method that calls {@link queueJob()} |
89 | * if {@link isTimeToQueueJob()} returns true. |
90 | * |
91 | * @since 0.1.7 |
92 | * @return bool Whether or not job was queued. |
93 | */ |
94 | public function maybeQueueJob() { |
95 | if ( $this->isTimeToQueueJob() ) { |
96 | $this->queueJob(); |
97 | return true; |
98 | } |
99 | return false; |
100 | } |
101 | |
102 | /** |
103 | * Queues a job. |
104 | * |
105 | * @since 0.1.7 |
106 | */ |
107 | public function queueJob() { |
108 | $this->cache->set( $this->cacheKey, new DateTime() ); |
109 | $jobQueueGroup = MediaWikiServices::getInstance()->getJobQueueGroup(); |
110 | $jobQueueGroup->push( |
111 | new FlushUtterancesFromStoreByExpirationJob( |
112 | Title::newMainPage(), |
113 | [] |
114 | ) |
115 | ); |
116 | } |
117 | |
118 | /** |
119 | * Evaluates if the criteria has been met to queue a job. |
120 | * Currently that means that at least as many minutes as defined in config |
121 | * has past since previous queueing of the job. |
122 | * |
123 | * @since 0.1.7 |
124 | * @return bool Whether or not it's time to queue the flush job |
125 | */ |
126 | public function isTimeToQueueJob() { |
127 | if ( !$this->minimumMinutesBetweenFlushExpiredUtterancesJobs ) { |
128 | return false; |
129 | } |
130 | $previousDateTimeQueued = $this->cache->get( $this->cacheKey ); |
131 | $this->logger->debug( __METHOD__ . ': ' . |
132 | 'previousDateTimeQueued {previousDateTimeQueued}', |
133 | [ 'previousDateTimeQueued' => $previousDateTimeQueued ] |
134 | ); |
135 | if ( !$previousDateTimeQueued ) { |
136 | // Either the cached value was never set or the cache is offline. |
137 | // In case of the latter, avoid queuing jobs on each request |
138 | // by requiring a cached value. This will set the initial cached value. |
139 | $this->cache->set( $this->cacheKey, new DateTime() ); |
140 | return false; |
141 | } |
142 | $nextPossibleJobQueueTimestamp = date_add( |
143 | $previousDateTimeQueued, |
144 | date_interval_create_from_date_string( |
145 | $this->minimumMinutesBetweenFlushExpiredUtterancesJobs . ' minutes' |
146 | ) |
147 | ); |
148 | if ( !$nextPossibleJobQueueTimestamp ) { |
149 | $this->logger->error( __METHOD__ . ': ' . |
150 | 'Unable to calculate next possible job queue DateTime.' |
151 | ); |
152 | return false; |
153 | } |
154 | return new DateTime() >= $nextPossibleJobQueueTimestamp; |
155 | } |
156 | } |