Page MenuHomePhorge

No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline