Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F585080
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/RELEASE-NOTES-1.44 b/RELEASE-NOTES-1.44
index 71b7e18013b..51fdc6dfc21 100644
--- a/RELEASE-NOTES-1.44
+++ b/RELEASE-NOTES-1.44
@@ -135,6 +135,8 @@ For notes on 1.43.x and older releases, see HISTORY.
* You can use LoggerFactory::getContext() to add extra context to all PSR-3
log events.
* New helper methods Html::addClass() and Html::expandClassList().
+* The new FeatureShutdown service can be used to provide controlled outages for
+ deprecated interfaces.
* …
=== External library changes in 1.44 ===
diff --git a/autoload.php b/autoload.php
index 22b630f6a03..86692d00e81 100644
--- a/autoload.php
+++ b/autoload.php
@@ -1356,6 +1356,7 @@ $wgAutoloadLocalClasses = [
'MediaWiki\\ExtensionInfo' => __DIR__ . '/includes/utils/ExtensionInfo.php',
'MediaWiki\\ExternalLinks\\ExternalLinksLookup' => __DIR__ . '/includes/ExternalLinks/ExternalLinksLookup.php',
'MediaWiki\\ExternalLinks\\LinkFilter' => __DIR__ . '/includes/ExternalLinks/LinkFilter.php',
+ 'MediaWiki\\FeatureShutdown' => __DIR__ . '/includes/FeatureShutdown.php',
'MediaWiki\\Feed\\AtomFeed' => __DIR__ . '/includes/Feed/AtomFeed.php',
'MediaWiki\\Feed\\ChannelFeed' => __DIR__ . '/includes/Feed/ChannelFeed.php',
'MediaWiki\\Feed\\FeedItem' => __DIR__ . '/includes/Feed/FeedItem.php',
diff --git a/docs/config-schema.yaml b/docs/config-schema.yaml
index 0de846f281d..55a98aa5f5e 100644
--- a/docs/config-schema.yaml
+++ b/docs/config-schema.yaml
@@ -8236,3 +8236,29 @@ config-schema:
OutputPipelineStages to add to the DefaultOutputPipeline.
@unstable EXPERIMENTAL
@since 1.43
+ FeatureShutdown:
+ default: []
+ type: array
+ description: |-
+ Allow temporarily disabling use of certain features. Useful for
+ large site operators to push people to newer APIs while still
+ keeping the breakage short and contained.
+ This should be an array, where a key is a feature name and the value
+ is an array of shutdown arrays, each containing the following keys:
+ 'start' => Shutdown start, parsed with strtotime(). (required)
+ 'end' => Shutdown end, parsed with strtotime(). (required)
+ 'percentage' => Number between 0 and 100. If set, only a certain
+ percentage of requests will be blocked.
+ For example:
+ @code
+ $wgFeatureShutdown = [
+ 'pre-1.24-tokens' => [
+ [
+ 'start' => '2021-07-01T00:00 +00:00',
+ 'end' => '2021-08-01T00:00 +00:00',
+ 'percentage' => 50,
+ ],
+ ],
+ ];
+ @encdode
+ @since 1.44
diff --git a/docs/config-vars.php b/docs/config-vars.php
index a3a849743ce..3db04d7092a 100644
--- a/docs/config-vars.php
+++ b/docs/config-vars.php
@@ -4526,3 +4526,9 @@ $wgEnableProtectionIndicators = null;
* @see MediaWiki\MainConfigSchema::OutputPipelineStages
*/
$wgOutputPipelineStages = null;
+
+/**
+ * Config variable stub for the FeatureShutdown setting, for use by phpdoc and IDEs.
+ * @see MediaWiki\MainConfigSchema::FeatureShutdown
+ */
+$wgFeatureShutdown = null;
diff --git a/includes/FeatureShutdown.php b/includes/FeatureShutdown.php
new file mode 100644
index 00000000000..ae891f1c036
--- /dev/null
+++ b/includes/FeatureShutdown.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki;
+
+use MediaWiki\Config\ServiceOptions;
+
+/**
+ * Helper to check if certain features should be temporarily disabled.
+ *
+ * @author Taavi Väänänen <hi@taavi.wtf>
+ * @since 1.44
+ */
+class FeatureShutdown {
+ /** @internal Only public for service wiring use. */
+ public const CONSTRUCTOR_OPTIONS = [
+ 'FeatureShutdown',
+ ];
+
+ /** @var array */
+ private $shutdowns;
+
+ /**
+ * @param ServiceOptions $options
+ */
+ public function __construct( ServiceOptions $options ) {
+ $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
+ $this->shutdowns = $options->get( 'FeatureShutdown' );
+ }
+
+ /**
+ * @param string $featureName
+ * @return array|null
+ */
+ public function findForFeature( string $featureName ): ?array {
+ if ( !isset( $this->shutdowns[$featureName] ) ) {
+ return null;
+ }
+
+ $time = time();
+ foreach ( $this->shutdowns[$featureName] as $shutdown ) {
+ if ( strtotime( $shutdown['start'] ) > $time || strtotime( $shutdown['end'] ) < $time ) {
+ continue;
+ }
+
+ if ( isset( $shutdown['percentage'] ) && rand( 0, 99 ) > $shutdown['percentage'] ) {
+ continue;
+ }
+
+ return $shutdown;
+ }
+
+ return null;
+ }
+}
diff --git a/includes/MainConfigNames.php b/includes/MainConfigNames.php
index 7daa50e52a8..0019debcb26 100644
--- a/includes/MainConfigNames.php
+++ b/includes/MainConfigNames.php
@@ -4542,4 +4542,10 @@ class MainConfigNames {
*/
public const OutputPipelineStages = 'OutputPipelineStages';
+ /**
+ * Name constant for the FeatureShutdown setting, for use with Config::get()
+ * @see MainConfigSchema::FeatureShutdown
+ */
+ public const FeatureShutdown = 'FeatureShutdown';
+
}
diff --git a/includes/MainConfigSchema.php b/includes/MainConfigSchema.php
index d08f7732979..6cff642ee7c 100644
--- a/includes/MainConfigSchema.php
+++ b/includes/MainConfigSchema.php
@@ -13221,6 +13221,38 @@ class MainConfigSchema {
'default' => [],
'type' => 'map',
];
+
+ /**
+ * Allow temporarily disabling use of certain features. Useful for
+ * large site operators to push people to newer APIs while still
+ * keeping the breakage short and contained.
+ *
+ * This should be an array, where a key is a feature name and the value
+ * is an array of shutdown arrays, each containing the following keys:
+ * 'start' => Shutdown start, parsed with strtotime(). (required)
+ * 'end' => Shutdown end, parsed with strtotime(). (required)
+ * 'percentage' => Number between 0 and 100. If set, only a certain
+ * percentage of requests will be blocked.
+ *
+ * For example:
+ * @code
+ * $wgFeatureShutdown = [
+ * 'pre-1.24-tokens' => [
+ * [
+ * 'start' => '2021-07-01T00:00 +00:00',
+ * 'end' => '2021-08-01T00:00 +00:00',
+ * 'percentage' => 50,
+ * ],
+ * ],
+ * ];
+ * @encdode
+ *
+ * @since 1.44
+ */
+ public const FeatureShutdown = [
+ 'default' => [],
+ 'type' => 'list',
+ ];
// endregion -- End Miscellaneous
}
diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php
index c49637fd5c8..beff58af73c 100644
--- a/includes/MediaWikiServices.php
+++ b/includes/MediaWikiServices.php
@@ -1173,6 +1173,14 @@ class MediaWikiServices extends ServiceContainer {
return $this->getService( 'ExternalStoreFactory' );
}
+ /**
+ * @since 1.44
+ * @return FeatureShutdown
+ */
+ public function getFeatureShutdown(): FeatureShutdown {
+ return $this->getService( 'FeatureShutdown' );
+ }
+
/**
* @since 1.35
*/
diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php
index 03d084b3c82..0cae1b6abb8 100644
--- a/includes/ServiceWiring.php
+++ b/includes/ServiceWiring.php
@@ -101,6 +101,7 @@ use MediaWiki\EditPage\IntroMessageBuilder;
use MediaWiki\EditPage\PreloadedContentBuilder;
use MediaWiki\EditPage\SpamChecker;
use MediaWiki\Export\WikiExporterFactory;
+use MediaWiki\FeatureShutdown;
use MediaWiki\FileBackend\FileBackendGroup;
use MediaWiki\FileBackend\LockManager\LockManagerGroupFactory;
use MediaWiki\FileRepo\RepoGroup;
@@ -861,6 +862,15 @@ return [
);
},
+ 'FeatureShutdown' => static function ( MediaWikiServices $services ): FeatureShutdown {
+ return new FeatureShutdown(
+ new ServiceOptions(
+ FeatureShutdown::CONSTRUCTOR_OPTIONS,
+ $services->getMainConfig()
+ )
+ );
+ },
+
'FileBackendGroup' => static function ( MediaWikiServices $services ): FileBackendGroup {
$mainConfig = $services->getMainConfig();
diff --git a/includes/config-schema.php b/includes/config-schema.php
index 7d0674c7681..0321e1905e6 100644
--- a/includes/config-schema.php
+++ b/includes/config-schema.php
@@ -2641,6 +2641,8 @@ return [
'EnableProtectionIndicators' => false,
'OutputPipelineStages' => [
],
+ 'FeatureShutdown' => [
+ ],
],
'type' => [
'ConfigRegistry' => 'object',
@@ -3144,6 +3146,7 @@ return [
'ShowLogoutConfirmation' => 'boolean',
'EnableProtectionIndicators' => 'boolean',
'OutputPipelineStages' => 'object',
+ 'FeatureShutdown' => 'array',
],
'mergeStrategy' => [
'TiffThumbnailType' => 'replace',
diff --git a/tests/phpunit/unit/includes/FeatureShutdownTest.php b/tests/phpunit/unit/includes/FeatureShutdownTest.php
new file mode 100644
index 00000000000..309474579df
--- /dev/null
+++ b/tests/phpunit/unit/includes/FeatureShutdownTest.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\Config\ServiceOptions;
+use MediaWiki\FeatureShutdown;
+
+/**
+ * @covers \MediaWiki\FeatureShutdown
+ * @author Taavi Väänänen <hi@taavi.wtf>
+ */
+class FeatureShutdownTest extends MediaWikiUnitTestCase {
+ public function testConstruct() {
+ $this->assertInstanceOf(
+ FeatureShutdown::class,
+ new FeatureShutdown(
+ new ServiceOptions(
+ FeatureShutdown::CONSTRUCTOR_OPTIONS,
+ [ 'FeatureShutdown' => [], ]
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider provideNotShutdown
+ */
+ public function testNotShutdown( array $shutdowns ) {
+ $fs = new FeatureShutdown(
+ new ServiceOptions(
+ FeatureShutdown::CONSTRUCTOR_OPTIONS,
+ [ 'FeatureShutdown' => $shutdowns, ]
+ )
+ );
+
+ $this->assertNull( $fs->findForFeature( 'legacy-bars' ) );
+ }
+
+ public static function provideNotShutdown(): array {
+ // reminder: each test case contains a name and an array of parameters,
+ // so the only parameter is an array but needs to be wrapped in another array
+ return [
+ 'Empty' => [ [] ],
+ 'Other feature configured' => [
+ [
+ 'legacy-foos' => [
+ [
+ 'start' => date( 'Y-m-d H:i:s', strtotime( '-1 week' ) ),
+ 'end' => date( 'Y-m-d H:i:s', strtotime( '+1 week' ) ),
+ ],
+ ],
+ ],
+ ],
+ 'Configured but empty' => [
+ [
+ 'legacy-bars' => [],
+ ],
+ ],
+ 'Configured but wrong time' => [
+ [
+ 'legacy-bars' => [
+ [
+ // Assuming those timestamps are long past
+ 'start' => '2016-01-01T00:00 +00:00',
+ 'end' => '2016-02-01T00:00 +00:00',
+ ],
+ ],
+ ],
+ ],
+ ];
+ }
+
+ public function testShutdown() {
+ $shutdown = [
+ 'start' => date( 'Y-m-d H:i:s', strtotime( '-1 week' ) ),
+ 'end' => date( 'Y-m-d H:i:s', strtotime( '+1 week' ) ),
+ ];
+
+ $fs = new FeatureShutdown(
+ new ServiceOptions(
+ FeatureShutdown::CONSTRUCTOR_OPTIONS,
+ [
+ 'FeatureShutdown' => [
+ 'legacy-bars' => [ $shutdown ],
+ ],
+ ]
+ )
+ );
+
+ $this->assertEquals( $shutdown, $fs->findForFeature( 'legacy-bars' ) );
+ }
+}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jul 5, 5:32 AM (7 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
227513
Default Alt Text
(12 KB)
Attached To
Mode
rMW mediawiki
Attached
Detach File
Event Timeline
Log In to Comment