Correct Aphlict websocket URI construction after PHP8 compatibility changes
[phabricator.git] / src / infrastructure / cluster / PhabricatorClusterServiceHealthRecord.php
blob252c1166536ae79c57b5c6dd8f30ca57e2c70eb9
1 <?php
3 class PhabricatorClusterServiceHealthRecord
4 extends Phobject {
6 private $cacheKey;
7 private $shouldCheck;
8 private $isHealthy;
9 private $upEventCount;
10 private $downEventCount;
12 public function __construct($cache_key) {
13 $this->cacheKey = $cache_key;
14 $this->readState();
17 /**
18 * Is the database currently healthy?
20 public function getIsHealthy() {
21 return $this->isHealthy;
25 /**
26 * Should this request check database health?
28 public function getShouldCheck() {
29 return $this->shouldCheck;
33 /**
34 * How many recent health checks were successful?
36 public function getUpEventCount() {
37 return $this->upEventCount;
41 /**
42 * How many recent health checks failed?
44 public function getDownEventCount() {
45 return $this->downEventCount;
49 /**
50 * Number of failures or successes we need to see in a row before we change
51 * the state.
53 public function getRequiredEventCount() {
54 // NOTE: If you change this value, update the "Cluster: Databases" docs.
55 return 5;
59 /**
60 * Seconds to wait between health checks.
62 public function getHealthCheckFrequency() {
63 // NOTE: If you change this value, update the "Cluster: Databases" docs.
64 return 3;
68 public function didHealthCheck($result) {
69 $now = microtime(true);
70 $check_frequency = $this->getHealthCheckFrequency();
71 $event_count = $this->getRequiredEventCount();
73 $record = $this->readHealthRecord();
75 $log = $record['log'];
76 foreach ($log as $key => $event) {
77 $when = idx($event, 'timestamp');
79 // If the log already has another nearby event, just ignore this one.
80 // We raced with another process and our result can just be thrown away.
81 if (($now - $when) <= $check_frequency) {
82 return $this;
86 $log[] = array(
87 'timestamp' => $now,
88 'up' => $result,
91 // Throw away older events which are now obsolete.
92 $log = array_slice($log, -$event_count);
94 $count_up = 0;
95 $count_down = 0;
96 foreach ($log as $event) {
97 if ($event['up']) {
98 $count_up++;
99 } else {
100 $count_down++;
104 // If all of the events are the same, change the state.
105 if ($count_up == $event_count) {
106 $record['up'] = true;
107 } else if ($count_down == $event_count) {
108 $record['up'] = false;
111 $record['log'] = $log;
113 $this->writeHealthRecord($record);
115 $this->isHealthy = $record['up'];
116 $this->shouldCheck = false;
117 $this->updateStatistics($record);
119 return $this;
123 private function readState() {
124 $now = microtime(true);
125 $check_frequency = $this->getHealthCheckFrequency();
127 $record = $this->readHealthRecord();
129 $last_check = $record['lastCheck'];
131 if (($now - $last_check) >= $check_frequency) {
132 $record['lastCheck'] = $now;
133 $this->writeHealthRecord($record);
134 $this->shouldCheck = true;
135 } else {
136 $this->shouldCheck = false;
139 $this->isHealthy = $record['up'];
140 $this->updateStatistics($record);
143 private function updateStatistics(array $record) {
144 $this->upEventCount = 0;
145 $this->downEventCount = 0;
146 foreach ($record['log'] as $event) {
147 if ($event['up']) {
148 $this->upEventCount++;
149 } else {
150 $this->downEventCount++;
155 public function getCacheKey() {
156 return $this->cacheKey;
159 private function readHealthRecord() {
160 $cache = PhabricatorCaches::getSetupCache();
161 $cache_key = $this->getCacheKey();
162 $health_record = $cache->getKey($cache_key);
164 if (!is_array($health_record)) {
165 $health_record = array(
166 'up' => true,
167 'lastCheck' => 0,
168 'log' => array(),
172 return $health_record;
175 private function writeHealthRecord(array $record) {
176 $cache = PhabricatorCaches::getSetupCache();
177 $cache_key = $this->getCacheKey();
178 $cache->setKey($cache_key, $record);