@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add a specialized cache for storing "has setup ever worked?"

Summary:
Ref T11613. In D16503/T11598 I refined the setup flow to improve messaging for early-stage setup issues, but failed to fully untangle things.

We sometimes still try to access a cache which uses configuration before we build configuration, which causes an error.

Instead, store "are we in flight / has setup ever worked?" in a separate cache which doesn't use the cache namespace. This stops us from trying to read config before building config.

Test Plan:
Hit bad extension error with a fake extension, got a proper setup help page:

{F1812803}

Solved the error, reloaded, broke things again, got a "friendly" page:

{F1812805}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11613

Differential Revision: https://secure.phabricator.com/D16542

+51 -14
+38 -5
src/applications/cache/PhabricatorCaches.php
··· 143 143 } 144 144 145 145 146 + /* -( Server State Cache )------------------------------------------------- */ 147 + 148 + 149 + /** 150 + * Highly specialized cache for storing server process state. 151 + * 152 + * We use this cache to track initial steps in the setup phase, before 153 + * configuration is loaded. 154 + * 155 + * This cache does NOT use the cache namespace (it must be accessed before 156 + * we build configuration), and is global across all instances on the host. 157 + * 158 + * @return PhutilKeyValueCacheStack Best available server state cache stack. 159 + * @task setup 160 + */ 161 + public static function getServerStateCache() { 162 + static $cache; 163 + if (!$cache) { 164 + $caches = self::buildSetupCaches('phabricator-server'); 165 + 166 + // NOTE: We are NOT adding a cache namespace here! This cache is shared 167 + // across all instances on the host. 168 + 169 + $caches = self::addProfilerToCaches($caches); 170 + $cache = id(new PhutilKeyValueCacheStack()) 171 + ->setCaches($caches); 172 + 173 + } 174 + return $cache; 175 + } 176 + 177 + 178 + 146 179 /* -( Setup Cache )-------------------------------------------------------- */ 147 180 148 181 ··· 163 196 public static function getSetupCache() { 164 197 static $cache; 165 198 if (!$cache) { 166 - $caches = self::buildSetupCaches(); 199 + $caches = self::buildSetupCaches('phabricator-setup'); 167 200 $cache = self::newStackFromCaches($caches); 168 201 } 169 202 return $cache; ··· 173 206 /** 174 207 * @task setup 175 208 */ 176 - private static function buildSetupCaches() { 209 + private static function buildSetupCaches($cache_name) { 177 210 // If this is the CLI, just build a setup cache. 178 211 if (php_sapi_name() == 'cli') { 179 212 return array(); ··· 188 221 189 222 // If we don't have APC, build a poor approximation on disk. This is still 190 223 // much better than nothing; some setup steps are quite slow. 191 - $disk_path = self::getSetupCacheDiskCachePath(); 224 + $disk_path = self::getSetupCacheDiskCachePath($cache_name); 192 225 if ($disk_path) { 193 226 $disk = new PhutilOnDiskKeyValueCache(); 194 227 $disk->setCacheFile($disk_path); ··· 205 238 /** 206 239 * @task setup 207 240 */ 208 - private static function getSetupCacheDiskCachePath() { 241 + private static function getSetupCacheDiskCachePath($name) { 209 242 // The difficulty here is in choosing a path which will change on server 210 243 // restart (we MUST have this property), but as rarely as possible 211 244 // otherwise (we desire this property to give the cache the best hit rate ··· 230 263 231 264 $tmp_dir = sys_get_temp_dir(); 232 265 233 - $tmp_path = $tmp_dir.DIRECTORY_SEPARATOR.'phabricator-setup'; 266 + $tmp_path = $tmp_dir.DIRECTORY_SEPARATOR.$name; 234 267 if (!file_exists($tmp_path)) { 235 268 @mkdir($tmp_path); 236 269 }
+5 -1
src/applications/config/check/PhabricatorSetupCheck.php
··· 74 74 $cache = PhabricatorCaches::getSetupCache(); 75 75 $cache->setKey('phabricator.setup.issue-keys', $keys); 76 76 77 + $server_cache = PhabricatorCaches::getServerStateCache(); 78 + $server_cache->setKey('phabricator.in-flight', 1); 79 + 77 80 if ($update_database) { 78 81 $db_cache = new PhabricatorKeyValueDatabaseCache(); 79 82 try { ··· 204 207 * @return bool True if we've made it through setup since the last restart. 205 208 */ 206 209 final public static function isInFlight() { 207 - return (self::getOpenSetupIssueKeys() !== null); 210 + $cache = PhabricatorCaches::getServerStateCache(); 211 + return (bool)$cache->getKey('phabricator.in-flight'); 208 212 } 209 213 210 214 final public static function loadAllChecks() {
+8 -8
src/infrastructure/env/PhabricatorEnv.php
··· 315 315 * @task read 316 316 */ 317 317 public static function getEnvConfig($key) { 318 - if (isset(self::$cache[$key])) { 319 - return self::$cache[$key]; 320 - } 321 - 322 - if (array_key_exists($key, self::$cache)) { 323 - return self::$cache[$key]; 324 - } 325 - 326 318 if (!self::$sourceStack) { 327 319 throw new Exception( 328 320 pht( 329 321 'Trying to read configuration "%s" before configuration has been '. 330 322 'initialized.', 331 323 $key)); 324 + } 325 + 326 + if (isset(self::$cache[$key])) { 327 + return self::$cache[$key]; 328 + } 329 + 330 + if (array_key_exists($key, self::$cache)) { 331 + return self::$cache[$key]; 332 332 } 333 333 334 334 $result = self::$sourceStack->getKeys(array($key));