diff --git a/vendor/magento/framework/Cache/Backend/RemoteSynchronizedCache.php b/vendor/magento/framework/Cache/Backend/RemoteSynchronizedCache.php
index 85218242057e4..7e0bb0897c062 100644
--- a/vendor/magento/framework/Cache/Backend/RemoteSynchronizedCache.php
+++ b/vendor/magento/framework/Cache/Backend/RemoteSynchronizedCache.php
@@ -1,7 +1,7 @@
 <?php
 /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
+ * Copyright 2018 Adobe
+ * All Rights Reserved.
  */
 
 namespace Magento\Framework\Cache\Backend;
@@ -17,6 +17,8 @@
  * in order to be sure that we always have up to date local version of cache.
  * This class will be check cache version from remote cache and in case it newer
  * than local one, it will update local one from remote cache a.k.a two level cache.
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  */
 class RemoteSynchronizedCache extends \Zend_Cache_Backend implements \Zend_Cache_Backend_ExtendedInterface
 {
@@ -90,44 +92,132 @@ public function __construct(array $options = [])
         parent::__construct($options);
 
         $universalOptions = array_diff_key($options, $this->_options);
+        $this->initializeLocalBackend($universalOptions);
+        $this->initializeRemoteBackend($universalOptions);
+        $this->lockSign = $this->generateLockSign();
+    }
+
+    /**
+     * Check if remote backend is available.
+     *
+     * @return bool
+     */
+    private function isRemoteAvailable(): bool
+    {
+        return $this->remote !== null;
+    }
+
+    /**
+     * Initialize local cache backend.
+     *
+     * @param array $universalOptions
+     * @return void
+     * @throws \Zend_Cache_Exception
+     */
+    private function initializeLocalBackend(array $universalOptions): void
+    {
+        if ($this->_options['local_backend'] === null) {
+            \Zend_Cache::throwException('local_backend option must be set');
+        }
+
+        if ($this->_options['local_backend'] instanceof \Zend_Cache_Backend_ExtendedInterface) {
+            $this->local = $this->_options['local_backend'];
+            return;
+        }
 
+        $this->local = \Zend_Cache::_makeBackend(
+            $this->_options['local_backend'],
+            array_merge($universalOptions, $this->_options['local_backend_options']),
+            $this->_options['local_backend_custom_naming'],
+            $this->_options['local_backend_autoload']
+        );
+
+        if (!($this->local instanceof \Zend_Cache_Backend_ExtendedInterface)) {
+            \Zend_Cache::throwException(
+                'local_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'
+            );
+        }
+    }
+
+    /**
+     * Initialize remote cache backend with graceful degradation.
+     *
+     * @param array $universalOptions
+     * @return void
+     * @throws \Zend_Cache_Exception
+     */
+    private function initializeRemoteBackend(array $universalOptions): void
+    {
         if ($this->_options['remote_backend'] === null) {
-            \Zend_Cache::throwException('remote_backend option must be set');
-        } elseif ($this->_options['remote_backend'] instanceof \Zend_Cache_Backend_ExtendedInterface) {
+            $this->handleMissingRemoteBackend();
+            return;
+        }
+
+        if ($this->_options['remote_backend'] instanceof \Zend_Cache_Backend_ExtendedInterface) {
             $this->remote = $this->_options['remote_backend'];
-        } else {
+            return;
+        }
+
+        $this->createRemoteBackend($universalOptions);
+    }
+
+    /**
+     * Handle missing remote backend configuration.
+     *
+     * @return void
+     * @throws \Zend_Cache_Exception
+     */
+    private function handleMissingRemoteBackend(): void
+    {
+        if (!$this->_options['use_stale_cache']) {
+            \Zend_Cache::throwException('remote_backend option must be set');
+        }
+        $this->remote = null;
+    }
+
+    /**
+     * Create remote backend instance with error handling.
+     *
+     * @param array $universalOptions
+     * @return void
+     * @throws \Zend_Cache_Exception|\Throwable
+     */
+    private function createRemoteBackend(array $universalOptions): void
+    {
+        try {
             $this->remote = \Zend_Cache::_makeBackend(
                 $this->_options['remote_backend'],
                 array_merge($universalOptions, $this->_options['remote_backend_options']),
                 $this->_options['remote_backend_custom_naming'],
                 $this->_options['remote_backend_autoload']
             );
+
             if (!($this->remote instanceof \Zend_Cache_Backend_ExtendedInterface)) {
-                \Zend_Cache::throwException(
+                $this->handleRemoteBackendFailure(
                     'remote_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'
                 );
             }
-        }
-
-        if ($this->_options['local_backend'] === null) {
-            \Zend_Cache::throwException('local_backend option must be set');
-        } elseif ($this->_options['local_backend'] instanceof \Zend_Cache_Backend_ExtendedInterface) {
-            $this->local = $this->_options['local_backend'];
-        } else {
-            $this->local = \Zend_Cache::_makeBackend(
-                $this->_options['local_backend'],
-                array_merge($universalOptions, $this->_options['local_backend_options']),
-                $this->_options['local_backend_custom_naming'],
-                $this->_options['local_backend_autoload']
-            );
-            if (!($this->local instanceof \Zend_Cache_Backend_ExtendedInterface)) {
-                \Zend_Cache::throwException(
-                    'local_backend must implement the Zend_Cache_Backend_ExtendedInterface interface'
-                );
+        } catch (\Throwable $e) {
+            if (!$this->_options['use_stale_cache']) {
+                throw $e;
             }
+            $this->remote = null;
         }
+    }
 
-        $this->lockSign = $this->generateLockSign();
+    /**
+     * Handle remote backend initialization failure.
+     *
+     * @param string $message
+     * @return void
+     * @throws \Zend_Cache_Exception
+     */
+    private function handleRemoteBackendFailure(string $message): void
+    {
+        if (!$this->_options['use_stale_cache']) {
+            \Zend_Cache::throwException($message);
+        }
+        $this->remote = null;
     }
 
     /**
@@ -135,7 +225,9 @@ public function __construct(array $options = [])
      */
     public function setDirectives($directives)
     {
-        $this->remote->setDirectives($directives);
+        if ($this->isRemoteAvailable()) {
+            $this->remote->setDirectives($directives);
+        }
         $this->local->setDirectives($directives);
     }
 
@@ -158,6 +250,9 @@ private function getDataVersion(string $data)
      */
     private function loadRemoteDataVersion(string $id)
     {
+        if ($this->remote === null) {
+            return false;
+        }
         return $this->remote->load(
             $id . self::HASH_SUFFIX
         );
@@ -174,6 +269,9 @@ private function loadRemoteDataVersion(string $id)
      */
     private function saveRemoteDataVersion(string $data, string $id, array $tags, $specificLifetime = false)
     {
+        if ($this->remote === null) {
+            return false;
+        }
         return $this->remote->save($this->getDataVersion($data), $id . self::HASH_SUFFIX, $tags, $specificLifetime);
     }
 
@@ -185,37 +283,152 @@ private function saveRemoteDataVersion(string $data, string $id, array $tags, $s
      */
     private function removeRemoteDataVersion($id)
     {
+        if ($this->remote === null) {
+            return false;
+        }
         return $this->remote->remove($id . self::HASH_SUFFIX);
     }
 
+    /**
+     * Synchronize local data to remote cache.
+     *
+     * @param string $data
+     * @param string $id
+     * @return bool
+     */
+    private function syncLocalToRemote(string $data, string $id): bool
+    {
+        if ($this->remote === null) {
+            return false;
+        }
+        try {
+            $remoteSaveResult = $this->remote->save($data, $id);
+            $remoteHashSaveResult = $this->saveRemoteDataVersion($data, $id, []);
+            return $remoteSaveResult && $remoteHashSaveResult;
+        } catch (\Throwable $e) {
+            return false;
+        }
+    }
+
     /**
      * @inheritdoc
      */
     public function load($id, $doNotTestCacheValidity = false)
     {
         $localData = $this->local->load($id);
+        $loadContext = [
+            'remoteHash' => false,
+            'isRemoteAccessible' => true
+        ];
 
-        if ($localData !== false) {
-            if ($this->getDataVersion($localData) === $this->loadRemoteDataVersion($id)) {
-                return $localData;
-            }
+        if ($localData !== false && $this->isLocalDataValid($id, $localData, $loadContext)) {
+            return $localData;
         }
 
-        $remoteData = $this->remote->load($id);
-        if ($remoteData !== false) {
-            $this->local->save($remoteData, $id);
+        $remoteResult = $this->loadFromRemote($id, $localData, $loadContext);
+        if ($remoteResult !== null) {
+            return $remoteResult;
+        }
 
-            return $remoteData;
-        } elseif ($localData && $this->_options['use_stale_cache']) {
-            if ($this->lock($id)) {
-                return false;
-            } else {
-                $this->notifyStaleCache();
-                return $localData;
-            }
+        return $this->handleStaleCacheFallback($id, $localData, $loadContext['isRemoteAccessible']);
+    }
+
+    /**
+     * Check if local data is valid by comparing with remote hash.
+     *
+     * @param string $id
+     * @param mixed $localData
+     * @param array $context
+     * @return bool
+     */
+    private function isLocalDataValid(string $id, $localData, array &$context): bool
+    {
+        try {
+            $context['remoteHash'] = $this->loadRemoteDataVersion($id);
+            $localHash = $this->getDataVersion($localData);
+
+            return $context['remoteHash'] !== false && $localHash === $context['remoteHash'];
+        } catch (\Throwable $e) {
+            $context['isRemoteAccessible'] = false;
+            return false;
         }
+    }
 
-        return false;
+    /**
+     * Load data from remote backend with sync logic.
+     *
+     * @param string $id
+     * @param mixed $localData
+     * @param array $context
+     * @return mixed|null Returns data if found, null if should continue to fallback
+     */
+    private function loadFromRemote(string $id, $localData, array &$context)
+    {
+        if (!$context['isRemoteAccessible'] || !$this->isRemoteAvailable()) {
+            $context['isRemoteAccessible'] = false;
+            return null;
+        }
+
+        try {
+            $remoteData = $this->remote->load($id);
+        } catch (\Throwable $e) {
+            $context['isRemoteAccessible'] = false;
+            return null;
+        }
+
+        if ($remoteData === false) {
+            return null;
+        }
+
+        if ($this->shouldUseLocalData($localData, $remoteData, $context['remoteHash'])) {
+            $this->syncLocalToRemote($localData, $id);
+            return $localData;
+        }
+
+        $this->local->save($remoteData, $id);
+        return $remoteData;
+    }
+
+    /**
+     * Determine if local data should be used instead of remote.
+     *
+     * @param mixed $localData
+     * @param mixed $remoteData
+     * @param mixed $remoteHash
+     * @return bool
+     */
+    private function shouldUseLocalData($localData, $remoteData, $remoteHash): bool
+    {
+        if ($localData === false || !$this->_options['use_stale_cache']) {
+            return false;
+        }
+
+        $localHash = $this->getDataVersion($localData);
+        $remoteDataHash = $this->getDataVersion($remoteData);
+
+        return $remoteHash === false || $localHash !== $remoteDataHash;
+    }
+
+    /**
+     * Handle stale cache fallback when remote is unavailable.
+     *
+     * @param string $id
+     * @param mixed $localData
+     * @param bool $isRemoteAccessible
+     * @return mixed
+     */
+    private function handleStaleCacheFallback(string $id, $localData, bool $isRemoteAccessible)
+    {
+        if (!$localData || !$this->_options['use_stale_cache']) {
+            return false;
+        }
+
+        if ($isRemoteAccessible && $this->lock($id)) {
+            return false;
+        }
+
+        $this->notifyStaleCache();
+        return $localData;
     }
 
     /**
@@ -223,9 +436,14 @@ public function load($id, $doNotTestCacheValidity = false)
      */
     public function test($id)
     {
-        return $this->_options['use_stale_cache'] ?
-            ($this->local->test($id) ?? $this->remote->test($id))
-            : $this->remote->test($id);
+        if ($this->_options['use_stale_cache']) {
+            $localTest = $this->local->test($id);
+            if ($localTest !== false) {
+                return $localTest;
+            }
+            return $this->isRemoteAvailable() ? $this->remote->test($id) : false;
+        }
+        return $this->isRemoteAvailable() ? $this->remote->test($id) : false;
     }
 
     /**
@@ -233,22 +451,98 @@ public function test($id)
      */
     public function save($data, $id, $tags = [], $specificLifetime = false)
     {
-        $dataToSave = $data;
-        $remHash = $this->loadRemoteDataVersion($id);
-        $isRemoteUpToDate = false;
-        if ($remHash !== false && $this->getDataVersion($data) === $remHash) {
+        $saveContext = $this->checkRemoteCache($data, $id);
+        $dataToSave = $saveContext['dataToSave'];
+        $remoteUpdateFailed = $saveContext['remoteFailed'];
+
+        if (!$saveContext['isUpToDate'] && !$remoteUpdateFailed) {
+            $remoteUpdateFailed = !$this->saveToRemote($data, $id, $tags, $specificLifetime);
+        }
+
+        $this->handlePostSaveCleanup($id, $remoteUpdateFailed);
+
+        // Local cache doesn't save tags intentionally since it will cause inconsistency after flushing the cache
+        // in multinode environment
+        return $this->local->save($dataToSave, $id, [], $specificLifetime);
+    }
+
+    /**
+     * Check if remote cache is up to date.
+     *
+     * @param mixed $data
+     * @param string $id
+     * @return array
+     */
+    private function checkRemoteCache($data, string $id): array
+    {
+        $result = [
+            'isUpToDate' => false,
+            'dataToSave' => $data,
+            'remoteFailed' => false
+        ];
+
+        if (!$this->isRemoteAvailable()) {
+            $result['remoteFailed'] = true;
+            return $result;
+        }
+
+        try {
+            $remHash = $this->loadRemoteDataVersion($id);
+            if ($remHash === false || $this->getDataVersion($data) !== $remHash) {
+                return $result;
+            }
+
             $remoteData = $this->remote->load($id);
             if ($remoteData !== false && $this->getDataVersion($data) === $this->getDataVersion($remoteData)) {
-                $isRemoteUpToDate = true;
-                $dataToSave = $remoteData;
+                $result['isUpToDate'] = true;
+                $result['dataToSave'] = $remoteData;
             }
+        } catch (\Throwable $e) {
+            $result['remoteFailed'] = true;
+        }
+
+        return $result;
+    }
+
+    /**
+     * Save data to remote backend.
+     *
+     * @param mixed $data
+     * @param string $id
+     * @param array $tags
+     * @param mixed $specificLifetime
+     * @return bool
+     */
+    private function saveToRemote($data, string $id, array $tags, $specificLifetime): bool
+    {
+        if (!$this->isRemoteAvailable()) {
+            return false;
         }
-        if (!$isRemoteUpToDate) {
-            $this->remote->save($data, $id, $tags, $specificLifetime);
-            $this->saveRemoteDataVersion($data, $id, $tags, $specificLifetime);
+
+        try {
+            $remoteSaveResult = $this->remote->save($data, $id, $tags, $specificLifetime);
+
+            if ($remoteSaveResult === false) {
+                return false;
+            }
+
+            $remoteHashSaveResult = $this->saveRemoteDataVersion($data, $id, $tags, $specificLifetime);
+            return $remoteHashSaveResult !== false;
+        } catch (\Throwable $e) {
+            return false;
         }
+    }
 
-        if ($this->_options['use_stale_cache']) {
+    /**
+     * Handle post-save cleanup operations.
+     *
+     * @param string $id
+     * @param bool $remoteUpdateFailed
+     * @return void
+     */
+    private function handlePostSaveCleanup(string $id, bool $remoteUpdateFailed): void
+    {
+        if ($this->_options['use_stale_cache'] && !$remoteUpdateFailed) {
             $this->unlock($id);
         }
 
@@ -257,10 +551,6 @@ public function save($data, $id, $tags = [], $specificLifetime = false)
         if (!mt_rand(0, 100) && $this->checkIfLocalCacheSpaceExceeded()) {
             $this->local->clean();
         }
-
-        // Local cache doesn't save tags intentionally since it will cause inconsistency after flushing the cache
-        // in multinode environment
-        return $this->local->save($dataToSave, $id, [], $specificLifetime);
     }
 
     /**
@@ -278,10 +568,21 @@ private function checkIfLocalCacheSpaceExceeded()
      */
     public function remove($id)
     {
-        $result = $this->removeRemoteDataVersion($id) && $this->remote->remove($id);
+        $result = false;
+        if ($this->isRemoteAvailable()) {
+            try {
+                $result = $this->removeRemoteDataVersion($id) && $this->remote->remove($id);
+            } catch (\Throwable $e) {
+                $result = false;
+            }
+        }
+
         if ($result && !$this->_options['use_stale_cache']) {
             $result = $this->local->remove($id);
+        } elseif (!$result && $this->_options['use_stale_cache']) {
+            $this->local->remove($id);
         }
+
         return $result;
     }
 
@@ -290,8 +591,18 @@ public function remove($id)
      */
     public function clean($mode = \Zend_Cache::CLEANING_MODE_ALL, $tags = [])
     {
-        return $this->remote->clean($mode, $tags) &&
-            $this->local->clean($mode);
+        $result = false;
+        if ($this->isRemoteAvailable()) {
+            try {
+                $result = $this->remote->clean($mode, $tags);
+            } catch (\Throwable $e) {
+                $result = false;
+            }
+        }
+
+        $localResult = $this->local->clean($mode);
+
+        return $result && $localResult;
     }
 
     /**
@@ -299,7 +610,10 @@ public function clean($mode = \Zend_Cache::CLEANING_MODE_ALL, $tags = [])
      */
     public function getIds()
     {
-        return $this->remote->getIds();
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getIds();
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getIds() : [];
     }
 
     /**
@@ -307,7 +621,10 @@ public function getIds()
      */
     public function getTags()
     {
-        return $this->remote->getTags();
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getTags();
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getTags() : [];
     }
 
     /**
@@ -315,7 +632,10 @@ public function getTags()
      */
     public function getIdsMatchingTags($tags = [])
     {
-        return $this->remote->getIdsMatchingTags($tags);
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getIdsMatchingTags($tags);
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getIdsMatchingTags($tags) : [];
     }
 
     /**
@@ -323,7 +643,10 @@ public function getIdsMatchingTags($tags = [])
      */
     public function getIdsNotMatchingTags($tags = [])
     {
-        return $this->remote->getIdsNotMatchingTags($tags);
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getIdsNotMatchingTags($tags);
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getIdsNotMatchingTags($tags) : [];
     }
 
     /**
@@ -331,7 +654,10 @@ public function getIdsNotMatchingTags($tags = [])
      */
     public function getIdsMatchingAnyTags($tags = [])
     {
-        return $this->remote->getIdsMatchingAnyTags($tags);
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getIdsMatchingAnyTags($tags);
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getIdsMatchingAnyTags($tags) : [];
     }
 
     /**
@@ -339,7 +665,10 @@ public function getIdsMatchingAnyTags($tags = [])
      */
     public function getFillingPercentage()
     {
-        return $this->remote->getFillingPercentage();
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getFillingPercentage();
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getFillingPercentage() : 0;
     }
 
     /**
@@ -347,7 +676,10 @@ public function getFillingPercentage()
      */
     public function getMetadatas($id)
     {
-        return $this->remote->getMetadatas($id);
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getMetadatas($id);
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->getMetadatas($id) : false;
     }
 
     /**
@@ -355,7 +687,10 @@ public function getMetadatas($id)
      */
     public function touch($id, $extraLifetime)
     {
-        return $this->remote->touch($id, $extraLifetime);
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->touch($id, $extraLifetime);
+        }
+        return $this->_options['use_stale_cache'] ? $this->local->touch($id, $extraLifetime) : false;
     }
 
     /**
@@ -363,7 +698,11 @@ public function touch($id, $extraLifetime)
      */
     public function getCapabilities()
     {
-        return $this->remote->getCapabilities();
+        if ($this->isRemoteAvailable()) {
+            return $this->remote->getCapabilities();
+        }
+
+        return $this->local->getCapabilities();
     }
 
     /**
@@ -374,6 +713,10 @@ public function getCapabilities()
      */
     private function lock(string $id): bool
     {
+        if (!$this->isRemoteAvailable()) {
+            return false;
+        }
+
         $this->lockList[$id] = microtime(true);
 
         $data = $this->remote->load($this->getLockName($id));
@@ -405,6 +748,10 @@ private function unlock(string $id): bool
             unset($this->lockList[$id]);
         }
 
+        if (!$this->isRemoteAvailable()) {
+            return false;
+        }
+
         $data = $this->remote->load($this->getLockName($id));
 
         if (false === $data) {
@@ -480,8 +827,13 @@ private function generateLockSign()
      */
     private function notifyStaleCache(): void
     {
-        $this->notifier = $this->notifier ??
-            ObjectManager::getInstance()->get(CompositeStaleCacheNotifier::class);
+        if ($this->notifier === null) {
+            try {
+                $this->notifier = ObjectManager::getInstance()->get(CompositeStaleCacheNotifier::class);
+            } catch (\Throwable $e) {
+                return;
+            }
+        }
         $this->notifier->cacheLoaderIsUsingStaleCache();
     }
 }
