comparison core/lib/Drupal/Core/Database/ReplicaKillSwitch.php @ 18:af1871eacc83

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:33:08 +0100
parents
children
comparison
equal deleted inserted replaced
17:129ea1e6d783 18:af1871eacc83
1 <?php
2
3 namespace Drupal\Core\Database;
4
5 use Drupal\Component\Datetime\TimeInterface;
6 use Drupal\Core\Site\Settings;
7 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8 use Symfony\Component\HttpFoundation\Session\SessionInterface;
9 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
10 use Symfony\Component\HttpKernel\KernelEvents;
11
12 /**
13 * Provides replica server kill switch to ignore it.
14 */
15 class ReplicaKillSwitch implements EventSubscriberInterface {
16
17 /**
18 * The settings object.
19 *
20 * @var \Drupal\Core\Site\Settings
21 */
22 protected $settings;
23
24 /**
25 * The time service.
26 *
27 * @var \Drupal\Component\Datetime\TimeInterface
28 */
29 protected $time;
30
31 /**
32 * The session.
33 *
34 * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
35 */
36 protected $session;
37
38 /**
39 * Constructs a ReplicaKillSwitch object.
40 *
41 * @param \Drupal\Core\Site\Settings $settings
42 * The settings object.
43 * @param \Drupal\Component\Datetime\TimeInterface $time
44 * The time service.
45 * @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
46 * The session.
47 */
48 public function __construct(Settings $settings, TimeInterface $time, SessionInterface $session) {
49 $this->settings = $settings;
50 $this->time = $time;
51 $this->session = $session;
52 }
53
54 /**
55 * Denies access to replica database on the current request.
56 *
57 * @see https://www.drupal.org/node/2286193
58 */
59 public function trigger() {
60 $connection_info = Database::getConnectionInfo();
61 // Only set ignore_replica_server if there are replica servers being used,
62 // which is assumed if there are more than one.
63 if (count($connection_info) > 1) {
64 // Five minutes is long enough to allow the replica to break and resume
65 // interrupted replication without causing problems on the Drupal site
66 // from the old data.
67 $duration = $this->settings->get('maximum_replication_lag', 300);
68 // Set session variable with amount of time to delay before using replica.
69 $this->session->set('ignore_replica_server', $this->time->getRequestTime() + $duration);
70 }
71 }
72
73 /**
74 * Checks and disables the replica database server if appropriate.
75 *
76 * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
77 * The Event to process.
78 */
79 public function checkReplicaServer(GetResponseEvent $event) {
80 // Ignore replica database servers for this request.
81 //
82 // In Drupal's distributed database structure, new data is written to the
83 // master and then propagated to the replica servers. This means there is a
84 // lag between when data is written to the master and when it is available
85 // on the replica. At these times, we will want to avoid using a replica
86 // server temporarily. For example, if a user posts a new node then we want
87 // to disable the replica server for that user temporarily to allow the
88 // replica server to catch up.
89 // That way, that user will see their changes immediately while for other
90 // users we still get the benefits of having a replica server, just with
91 // slightly stale data. Code that wants to disable the replica server should
92 // use the 'database.replica_kill_switch' service's trigger() method to set
93 // 'ignore_replica_server' session flag to the timestamp after which the
94 // replica can be re-enabled.
95 if ($this->session->has('ignore_replica_server')) {
96 if ($this->session->get('ignore_replica_server') >= $this->time->getRequestTime()) {
97 Database::ignoreTarget('default', 'replica');
98 }
99 else {
100 $this->session->remove('ignore_replica_server');
101 }
102 }
103 }
104
105 /**
106 * {@inheritdoc}
107 */
108 public static function getSubscribedEvents() {
109 $events[KernelEvents::REQUEST][] = ['checkReplicaServer'];
110 return $events;
111 }
112
113 }