class ReplicaKillSwitch

Same name in other branches
  1. 9 core/lib/Drupal/Core/Database/ReplicaKillSwitch.php \Drupal\Core\Database\ReplicaKillSwitch
  2. 8.9.x core/lib/Drupal/Core/Database/ReplicaKillSwitch.php \Drupal\Core\Database\ReplicaKillSwitch
  3. 11.x core/lib/Drupal/Core/Database/ReplicaKillSwitch.php \Drupal\Core\Database\ReplicaKillSwitch

Provides replica server kill switch to ignore it.

Hierarchy

  • class \Drupal\Core\Database\ReplicaKillSwitch implements \Symfony\Component\EventDispatcher\EventSubscriberInterface

Expanded class hierarchy of ReplicaKillSwitch

1 file declares its use of ReplicaKillSwitch
MenuRouterRebuildSubscriber.php in core/lib/Drupal/Core/EventSubscriber/MenuRouterRebuildSubscriber.php
1 string reference to 'ReplicaKillSwitch'
core.services.yml in core/core.services.yml
core/core.services.yml
1 service uses ReplicaKillSwitch
database.replica_kill_switch in core/core.services.yml
Drupal\Core\Database\ReplicaKillSwitch

File

core/lib/Drupal/Core/Database/ReplicaKillSwitch.php, line 15

Namespace

Drupal\Core\Database
View source
class ReplicaKillSwitch implements EventSubscriberInterface {
    
    /**
     * The settings object.
     *
     * @var \Drupal\Core\Site\Settings
     */
    protected $settings;
    
    /**
     * The time service.
     *
     * @var \Drupal\Component\Datetime\TimeInterface
     */
    protected $time;
    
    /**
     * The session.
     *
     * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
     */
    protected $session;
    
    /**
     * Constructs a ReplicaKillSwitch object.
     *
     * @param \Drupal\Core\Site\Settings $settings
     *   The settings object.
     * @param \Drupal\Component\Datetime\TimeInterface $time
     *   The time service.
     * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
     *   The session.
     */
    public function __construct(Settings $settings, TimeInterface $time, SessionInterface $session) {
        $this->settings = $settings;
        $this->time = $time;
        $this->session = $session;
    }
    
    /**
     * Denies access to replica database on the current request.
     *
     * @see https://www.drupal.org/node/2286193
     */
    public function trigger() {
        $connection_info = Database::getConnectionInfo();
        // Only set ignore_replica_server if there are replica servers being used,
        // which is assumed if there are more than one.
        if (count($connection_info) > 1) {
            // Five minutes is long enough to allow the replica to break and resume
            // interrupted replication without causing problems on the Drupal site
            // from the old data.
            $duration = $this->settings
                ->get('maximum_replication_lag', 300);
            // Set session variable with amount of time to delay before using replica.
            $this->session
                ->set('ignore_replica_server', $this->time
                ->getRequestTime() + $duration);
        }
    }
    
    /**
     * Checks and disables the replica database server if appropriate.
     *
     * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
     *   The Event to process.
     */
    public function checkReplicaServer(RequestEvent $event) {
        // Ignore replica database servers for this request.
        //
        // In Drupal's distributed database structure, new data is written to the
        // master and then propagated to the replica servers.  This means there is a
        // lag between when data is written to the master and when it is available
        // on the replica. At these times, we will want to avoid using a replica
        // server temporarily. For example, if a user posts a new node then we want
        // to disable the replica server for that user temporarily to allow the
        // replica server to catch up.
        // That way, that user will see their changes immediately while for other
        // users we still get the benefits of having a replica server, just with
        // slightly stale data. Code that wants to disable the replica server should
        // use the 'database.replica_kill_switch' service's trigger() method to set
        // 'ignore_replica_server' session flag to the timestamp after which the
        // replica can be re-enabled.
        if ($this->session
            ->has('ignore_replica_server')) {
            if ($this->session
                ->get('ignore_replica_server') >= $this->time
                ->getRequestTime()) {
                Database::ignoreTarget('default', 'replica');
            }
            else {
                $this->session
                    ->remove('ignore_replica_server');
            }
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() : array {
        $events[KernelEvents::REQUEST][] = [
            'checkReplicaServer',
        ];
        return $events;
    }

}

Members

Title Sort descending Modifiers Object type Summary
ReplicaKillSwitch::$session protected property The session.
ReplicaKillSwitch::$settings protected property The settings object.
ReplicaKillSwitch::$time protected property The time service.
ReplicaKillSwitch::checkReplicaServer public function Checks and disables the replica database server if appropriate.
ReplicaKillSwitch::getSubscribedEvents public static function
ReplicaKillSwitch::trigger public function Denies access to replica database on the current request.
ReplicaKillSwitch::__construct public function Constructs a ReplicaKillSwitch object.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.