125 if ( $this->procCache !==
null ) {
129 $now = microtime(
true );
130 $key = $this->srvCache->makeGlobalKey(
139 $loop =
new WaitConditionLoop(
140 function () use ( $key, $now, &$data, &$error ) {
142 $data = $this->srvCache->get( $key );
143 if ( is_array( $data ) && $data[
'expires'] > $now ) {
144 $this->logger->debug(
"Found up-to-date etcd configuration cache." );
146 return WaitConditionLoop::CONDITION_REACHED;
151 if ( $this->srvCache->lock( $key, 0, $this->baseCacheTTL ) ) {
153 list( $config, $error, $retry ) = $this->fetchAllFromEtcd();
154 if ( is_array( $config ) ) {
156 $expiry = microtime( true ) + $this->baseCacheTTL;
157 $expiry += mt_rand( 0, 1e6 ) / 1e6 * $this->skewCacheTTL;
159 $data = [
'config' => $config,
'expires' => $expiry ];
160 $this->srvCache->set( $key, $data, BagOStuff::TTL_INDEFINITE );
162 $this->logger->info(
"Refreshed stale etcd configuration cache." );
164 return WaitConditionLoop::CONDITION_REACHED;
166 $this->logger->error(
"Failed to fetch configuration: $error" );
169 return WaitConditionLoop::CONDITION_FAILED;
173 $this->srvCache->unlock( $key );
177 if ( is_array( $data ) ) {
178 $this->logger->info(
"Using stale etcd configuration cache." );
180 return WaitConditionLoop::CONDITION_REACHED;
183 return WaitConditionLoop::CONDITION_CONTINUE;
188 if ( $loop->invoke() !== WaitConditionLoop::CONDITION_REACHED ) {
190 throw new ConfigException(
"Failed to load configuration from etcd: $error" );
193 $this->procCache = $data;
201 $servers = $dsd->getServers();
203 return $this->fetchAllFromEtcdServer( $this->host );
208 $server = $dsd->pickServer( $servers );
209 $host = IP::combineHostAndPort( $server[
'target'], $server[
'port'] );
211 list( $config, $error, $retry ) = $this->fetchAllFromEtcdServer( $host );
212 if ( is_array( $config ) || !$retry ) {
217 $servers = $dsd->removeServer( $server, $servers );
218 }
while ( $servers );
220 return [ $config, $error, $retry ];
229 list( $rcode, $rdesc, , $rbody, $rerr ) = $this->
http->run( [
231 'url' =>
"{$this->protocol}://{$address}/v2/keys/{$this->directory}/?recursive=true",
232 'headers' => [
'content-type' =>
'application/json' ]
235 static $terminalCodes = [ 404 =>
true ];
236 if ( $rcode < 200 || $rcode > 399 ) {
239 strlen( $rerr ) ? $rerr :
"HTTP $rcode ($rdesc)",
240 empty( $terminalCodes[$rcode] )
244 return [ $this->parseResponse( $rbody ),
null,
false ];
246 return [
null,
$e->getMessage(),
false ];