* Added $wgAuthenticationTokenVersion, which if non-null prevents the
user_token database field from being exposed in cookies. Setting this would
be a good idea, but will log out all current sessions.
+* $wgEventRelayerConfig was added, for managing PubSub event relay configuration,
+ specifically for reliable CDN url purges.
=== External library changes in 1.27 ===
'EraseArchivedFile' => __DIR__ . '/maintenance/eraseArchivedFile.php',
'ErrorPageError' => __DIR__ . '/includes/exception/ErrorPageError.php',
'EventRelayer' => __DIR__ . '/includes/libs/eventrelayer/EventRelayer.php',
+ 'EventRelayerGroup' => __DIR__ . '/includes/EventRelayerGroup.php',
'EventRelayerMCRD' => __DIR__ . '/includes/libs/eventrelayer/EventRelayerMCRD.php',
'EventRelayerNull' => __DIR__ . '/includes/libs/eventrelayer/EventRelayer.php',
'Exif' => __DIR__ . '/includes/media/Exif.php',
*/
$wgMaxUserDBWriteDuration = false;
+/**
+ * Mapping of event channels to EventRelayer configuration.
+ *
+ * By setting up a PubSub system (like Kafka) and enabling a corresponding EventRelayer class
+ * that uses it, MediaWiki can broadcast events to all subscribers. Certain features like WAN
+ * cache purging and CDN cache purging will emit events to this system. Appropriate listers can
+ * subscribe to the channel and take actions based on the events. For example, a local daemon
+ * can run on each CDN cache node and perfom local purges based on the URL purge channel events.
+ *
+ * The 'default' channel is for all channels without an explicit entry here.
+ *
+ * @since 1.27
+ */
+$wgEventRelayerConfig = array(
+ 'default' => array(
+ 'class' => 'EventRelayerNull',
+ )
+);
+
/**
* For really cool vim folding this needs to be at the end:
* vim: foldmarker=@{,@} foldmethod=marker
--- /dev/null
+<?php
+/**
+ * Factory class for spawning EventRelayer objects using configuration
+ *
+ * @author Aaron Schulz
+ * @since 1.27
+ */
+class EventRelayerGroup {
+ /** @var array[] */
+ protected $configByChannel = array();
+
+ /** @var EventRelayer[] */
+ protected $relayers = array();
+
+ /** @var EventRelayerGroup */
+ protected static $instance = null;
+
+ /**
+ * @param Config $config
+ */
+ protected function __constuct( Config $config ) {
+ $this->configByChannel = $config->get( 'EventRelayerConfig' );
+ }
+
+ /**
+ * @return EventRelayerGroup
+ */
+ public static function singleton() {
+ if ( !self::$instance ) {
+ self::$instance = new self( RequestContext::getMain()->getConfig() );
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * @param string $channel
+ * @return EventRelayer Relayer instance that handles the given channel
+ */
+ public function getRelayer( $channel ) {
+ $channelKey = isset( $this->configByChannel[$channel] )
+ ? $channel
+ : 'default';
+
+ if ( !isset( $this->relayers[$channelKey] ) ) {
+ if ( !isset( $this->configByChannel[$channelKey] ) ) {
+ throw new UnexpectedValueException( "No config for '$channelKey'" );
+ }
+
+ $config = $this->configByChannel[$channelKey];
+ $class = $config['class'];
+
+ $this->relayers[$channelKey] = new $class( $config );
+ }
+
+ return $this->relayers[$channelKey];
+ }
+}
wfDebugLog( 'squid', __METHOD__ . ': ' . implode( ' ', $urlArr ) );
+ // Reliably broadcast the purge to all edge nodes
+ $relayer = EventRelayerGroup::singleton()->getRelayer( 'cdn-url-purges' );
+ $relayer->notify(
+ 'cdn-url-purges',
+ array(
+ 'urls' => array_values( $urlArr ), // JSON array
+ 'timestamp' => microtime( true )
+ )
+ );
+
+ // Send lossy UDP broadcasting if enabled
if ( $wgHTCPRouting ) {
self::HTCPPurge( $urlArr );
}
+ // Do direct server purges if enabled (this does not scale very well)
if ( $wgSquidServers ) {
// Maximum number of parallel connections per squid
$maxSocketsPerSquid = 8;