فهرست منبع

Add retries and failover of all jsons to cache even if the main one worked

Jordi Boggiano 12 سال پیش
والد
کامیت
1d80720405
1فایلهای تغییر یافته به همراه47 افزوده شده و 27 حذف شده
  1. 47 27
      src/Composer/Repository/ComposerRepository.php

+ 47 - 27
src/Composer/Repository/ComposerRepository.php

@@ -35,6 +35,7 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
     protected $loader;
     private $rawData;
     private $minimalPackages;
+    private $degradedMode = false;
 
     public function __construct(array $repoConfig, IOInterface $io, Config $config)
     {
@@ -201,34 +202,21 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
             throw new \RuntimeException('You must enable the openssl extension in your php.ini to load information from '.$this->url);
         }
 
-        try {
-            $jsonUrlParts = parse_url($this->url);
+        $jsonUrlParts = parse_url($this->url);
 
-            if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '/packages.json')) {
-                $jsonUrl = $this->url;
-            } else {
-                $jsonUrl = $this->url . '/packages.json';
-            }
-
-            $json = new JsonFile($jsonUrl, new RemoteFilesystem($this->io, $this->options));
-            $data = $json->read();
+        if (isset($jsonUrlParts['path']) && false !== strpos($jsonUrlParts['path'], '/packages.json')) {
+            $jsonUrl = $this->url;
+        } else {
+            $jsonUrl = $this->url . '/packages.json';
+        }
 
-            if (!empty($data['notify'])) {
-                if ('/' === $data['notify'][0]) {
-                    $this->notifyUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $data['notify'], $this->url);
-                } else {
-                    $this->notifyUrl = $data['notify'];
-                }
-            }
+        $data = $this->fetchFile($jsonUrl, 'packages.json');
 
-            $this->cache->write('packages.json', json_encode($data));
-        } catch (\Exception $e) {
-            if ($contents = $this->cache->read('packages.json')) {
-                $this->io->write('<warning>'.$e->getMessage().'</warning>');
-                $this->io->write('<warning>'.$this->url.' could not be loaded, package information was loaded from the local cache and may be out of date</warning>');
-                $data = json_decode($contents, true);
+        if (!empty($data['notify'])) {
+            if ('/' === $data['notify'][0]) {
+                $this->notifyUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $data['notify'], $this->url);
             } else {
-                throw $e;
+                $this->notifyUrl = $data['notify'];
             }
         }
 
@@ -263,9 +251,7 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
                 if ($this->cache->sha1($include) === $metadata['sha1']) {
                     $includedData = json_decode($this->cache->read($include), true);
                 } else {
-                    $json = new JsonFile($this->url.'/'.$include, new RemoteFilesystem($this->io));
-                    $includedData = $json->read();
-                    $this->cache->write($include, json_encode($includedData));
+                    $includedData = $this->fetchFile($include);
                 }
                 $packages = array_merge($packages, $this->loadIncludes($includedData));
             }
@@ -282,4 +268,38 @@ class ComposerRepository extends ArrayRepository implements NotifiableRepository
             throw new \RuntimeException('Could not load package '.(isset($data['name']) ? $data['name'] : json_encode($data)).' in '.$this->url.': ['.get_class($e).'] '.$e->getMessage(), 0, $e);
         }
     }
+
+    protected function fetchFile($filename, $cacheKey = null)
+    {
+        if (!$cacheKey) {
+            $cacheKey = $filename;
+            $filename = $this->url.'/'.$filename;
+        }
+
+        $retries = 3;
+        while ($retries--) {
+            try {
+                $json = new JsonFile($filename, new RemoteFilesystem($this->io));
+                $data = $json->read();
+                $this->cache->write($cacheKey, json_encode($data));
+
+                break;
+            } catch (\Exception $e) {
+                if ($contents = $this->cache->read($cacheKey)) {
+                    if (!$this->degradedMode) {
+                        $this->io->write('<warning>'.$e->getMessage().'</warning>');
+                        $this->io->write('<warning>'.$this->url.' could not be fully loaded, package information was loaded from the local cache and may be out of date</warning>');
+                    }
+                    $this->degradedMode = true;
+                    $data = json_decode($contents, true);
+                } elseif (!$retries) {
+                    throw $e;
+                }
+
+                usleep(100);
+            }
+        }
+
+        return $data;
+    }
 }