Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Varnish cache issue with 'Sign In' link in header #9156

Closed
rav-redchamps opened this issue Apr 6, 2017 · 20 comments
Closed

Varnish cache issue with 'Sign In' link in header #9156

rav-redchamps opened this issue Apr 6, 2017 · 20 comments
Labels
Issue: Clear Description Gate 2 Passed. Manual verification of the issue description passed Issue: Confirmed Gate 3 Passed. Manual verification of the issue completed. Issue is confirmed Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed Issue: Ready for Work Gate 4. Acknowledged. Issue is added to backlog and ready for development Reproduced on 2.1.x The issue has been reproduced on latest 2.1 release Reproduced on 2.2.x The issue has been reproduced on latest 2.2 release Reproduced on 2.3.x The issue has been reproduced on latest 2.3 release

Comments

@rav-redchamps
Copy link
Contributor

Hi Magento Team,

We found an issue with caching of 'Sign In' link in the header when varnish cache is setup on Magento 2.1.5.

Steps to reproduce are:

1.Go to home page
2.Click 'Sign In' from header
3.Enter login credentials to enter customer account
4.Click website logo to go back to home page
5.Notice that on the home page the header is still showing 'Sign In' instead of showing the customer is logged in and a 'Sign Out' link.

@AirmanAJK
Copy link

Varnish keeps caches separate for clients who have different cookies for the key "X-Magento-Vary". When you aren't signed in at all, the cookie value doesn't exist. When you do sign in, a cookie value will be set based on your customer group (and one or two other factors IIRC). If your VCL file isn't configured properly, it may not be hashing on the X-Magenty-Vary.

Here's what I would verify before going any further. Before signing in, examine your cookie to ensure you DO NOT find an X-Magento-Vary key. This can be done in the Chrome developer tools in the Network tab, but is beyond the scope of this response. Next, sign in and make sure you DO have the X-Magento-Vary cookie, and that it has a long hash value assigned to it. If all that is working properly, but you are still seeing improperly cached pages, examine your Varnish VCL file. This is the one you should have generated in the Magento admin section and then configured to be used by Varnish. If you skipped that step, this is DEFINITELY why you have caching problems.

The important part of the VCL file is as follows:

sub vcl_hash {
    if (req.http.cookie ~ "X-Magento-Vary=") {
        hash_data(regsub(req.http.cookie, "^.*?X-Magento-Vary=([^;]+);*.*$", "\1"));
    }

The default varnish behavior is not acceptable to be used in Magento as there are many Magento-specific rules that need to be in place.

@rav-redchamps
Copy link
Contributor Author

Hi @AirmanAJK

Thanks for your response.

Our varnish vcl file was generated using admin and it does contain below code

sub vcl_hash {
if (req.http.cookie ~ "X-Magento-Vary=") {
hash_data(regsub(req.http.cookie, "^.?X-Magento-Vary=([^;]+);.*$", "\1"));
}

Also, I have verified that

  • When I first reach home page there is not cookie with name "X-Magento-Vary"
  • When I login by clicking Sign In link the cookie with name "X-Magento-Vary" gets created

But when I go back to the home page by clicking website logo then links are cached and the cookie is not there. Now when I refreshed home page cookie gets created and links have been updated.

Next, when I click Sign Out from home page, the customer gets logout but the home page still has 'Sign Out' link and cookie is not there.


Another weird case, after flushing 'full page cache' from admin. If I try same steps as above, cookie doesn't get created after customer login as well.

It seems the cookies are getting itself. It will be awesome to have your thoughts on this.

@AirmanAJK
Copy link

Are you using a Redis to store the session and cache? If so, make sure you are storing them in different Redis databases. Varnish can cache pages incorrectly if a request comes in from the client with an invalid/expired session. This is because Varnish trusts the X-Magento-Vary header sent in the cookie. If the user isn't actually logged in (due to an old or flushed session), the page will still be cached by Varnish as whatever the incoming request claimed it was, even if Magento generates a different kind of page. This could be what you are experiencing.

You should also make sure that your pages aren't being cached by the browser. Varnish is supposed to examine the Magento response headers for Cache-Control and unset them for the response that gets to the client/browser. If somehow those are getting to your browser, it will keep stale pages and not even reach out to the server for updates. You can see in the browser dev tools if the page was loaded from cache or server, and you can also examine the response pages to see what cache headers are actually being set. You always want page requests to be non-cached by the browser. Magento's Varnish VCL happens to use the same headers as the browser for caching, so if somehow they aren't getting unset before getting sent off to the client, this could be your issue. If clearing your local browser cache ends up loading the correct page, this is the problem.

@rav-redchamps
Copy link
Contributor Author

I have checked this in multiple browsers chrome, firefox, safari with cache cleaned but same behavior in all browsers.

We do use Redis and below is configuration of it

'cache' =>
array (
'frontend' =>
array (
'default' =>
array (
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' =>
array (
'server' => 'unix:///var/tmp/redis-multi_website_name.com_default.sock',
'port' => '6379',
'persistent' => '',
'database' => 0,
'password' => '',
'force_standalone' => 1,
'connect_retries' => 1,
),
),
'page_cache' =>
array (
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' =>
array (
'server' => 'unix:///var/tmp/redis-multi_website_name.com_pagecache.sock',
'port' => '6379',
'persistent' => '',
'database' => 0,
'password' => '',
'force_standalone' => 1,
'connect_retries' => 1,
),
),
),
),

@southerncomputer
Copy link
Contributor

'session' =>
array (
'save' => 'redis',
'redis' =>
array (
'host' => '127.0.0.1',
'port' => '6379',
'password' => '',
'timeout' => '2.5',
'persistent_identifier' => '',
'database' => '2',
'compression_threshold' => '2048',
'compression_library' => 'gzip',
'log_level' => '1',
'max_concurrency' => '6',
'break_after_frontend' => '5',
'break_after_adminhtml' => '30',
'first_lifetime' => '600',
'bot_first_lifetime' => '60',
'bot_lifetime' => '7200',
'disable_locking' => '0',
'min_lifetime' => '60',
'max_lifetime' => '2592000'
)
),

^^ Sessions in redis..
what about sessions? You want them in redis for sure!

I'd recommend using varnish instead of storing page_cache in redis! it is duplicate work cut that page_cache out of the config and drop in the session portion! then use varnish 4 with a properly created varnish.vcl !

@AirmanAJK
Copy link

You said you were using Varnish for full page caching, but have Redis configured for full page caching as well? This looks like a bad setup.

Also, I wasn't asking you to make sure your browser cache was cleared, I was asking you to make sure your browser is never ever letting pages into its cache to begin with. I believe your pages are being cached by the client. Make sure your response headers for page requests have a Cache-Control value of "no-store, no-cache, must-revalidate, max-age=0".

This doesn't appear to be a Magento issue. It is likely a misconfiguration of Magento/Varnish/Redis.

@thdoan
Copy link

thdoan commented May 22, 2017

We are also having this issue since upgrading to v2.1.5. It was working just fine before that with this code (simplified):

<li data-bind="scope: 'customer'">
  <!-- ko if: customer().firstname  -->
  <a href="<?php echo $this->getUrl('customer/account/logout'); ?>"><?php echo __('Sign Out') ?></a>
  <!-- /ko -->
  <!-- ko ifnot: customer().firstname  -->
  <a href="<?php echo $this->getUrl('customer/account/login'); ?>"><?php echo __('Sign In') ?></a>
  <!-- /ko -->
  <script type="text/x-magento-init">
  {
      "*": {
          "Magento_Ui/js/core/app": {
              "components": {
                  "customer": {
                      "component": "Magento_Customer/js/view/customer"
                  }
              }
          }
      }
  }
  </script>
</li>

Now, even when signed in the customer object is empty ({}), so the "Sign In" link is rendered instead of "Sign Out". This is happening in production mode with both FPC and Varnish enabled.

@mrkhoa99
Copy link
Contributor

mrkhoa99 commented May 22, 2017

@thdoan I faced the same issue. Because the local storage is "added" after our script (Not sure it's a bug or not). Work Around: My idea is to check local storage until it is "added"- (we should override Magento_Customer/js/view/customer)

For example:

    var self = this;
        var time = setInterval(function () {
            self.customer = customerData.get('customer');
            if (localStorage["mage-cache-storage"] != '{}') {
                clearInterval(time);
            }
            
        }, 1000);

We also need to use customer: ko.observable({}), for customer object.

@thdoan
Copy link

thdoan commented May 22, 2017

@mrkhoa99 thanks for the suggestion. Do you have a workaround that doesn't involve overriding? I'm leaning towards two other alternatives for a quick fix:

  1. check cookie
  2. custom ajax controller that simply returns $this->_customerSession->isLoggedIn()

I would prefer to use the KO method since Magento uses it themsleves in vendor/magento/module-theme/view/frontend/templates/html/header.phtml.

@mrkhoa99
Copy link
Contributor

mrkhoa99 commented May 22, 2017

@thdoan

app/code/Vendor/Theme/etc/frontend/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Header" type="Vendor\Theme\Block\Html\Header"/>
</config>

app/code/Vendor/Theme/Block/Html/Header.php

<?php

namespace Vendor\Theme\Block\Html;

use Magento\Framework\View\Element\Template\Context;
use Magento\Theme\Block\Html\Header as HeaderBlock;
use Magento\Framework\App\Http\Context as CustomerContext;


class Header extends HeaderBlock
{
    /**
     * Current template name
     *
     * @var string
     */
    protected $_template = 'Vendor_Theme::html/header.phtml';

    /**
     * @var CustomerContext
     */
    protected $customerContext;

    /**
     * Header constructor.
     *
     * @param Context $context
     * @param CustomerContext $customerContext
     * @param array $data
     */
    public function __construct(
        Context $context,
        CustomerContext $customerContext,
        array $data = []
    ) {
        $this->customerContext = $customerContext;
        parent::__construct($context, $data);
    }

    /**
     * Check is Customer Logged In
     *
     * @return int
     */
    public function isCustomerLoggedIn()
    {
        $isLoggedIn = $this->customerContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH);
        return $isLoggedIn ? 1 : 0 ;
    }
}

app/code/Vendor/Theme/view/frontend/templates/html/header.phtml

<?php
// @codingStandardsIgnoreFile

/**
 * @var \Magento\Theme\Block\Html\Header $block
 */
$welcomeMessage = $block->getWelcome();
?>
<?php switch ($block->getShowPart()):
    case 'welcome': ?>
        <li class="greet welcome" data-bind="scope: 'customer'">
            <!-- ko if: isLoggedIn()  -->
            <span data-bind="text: htmlLoggedMessage()">
            </span>
            <!-- /ko -->
            <!-- ko ifnot: isLoggedIn()  -->
            <span data-bind="html:'<?=$block->escapeHtml($welcomeMessage) ?>'"></span>
            <!-- /ko -->
        </li>
        <script type="text/x-magento-init">
        {
            "*": {
                "Magento_Ui/js/core/app": {
                    "components": {
                        "customer": {
                            "component": "Vendor_Theme/js/view/customer",
                            "isCustomerLogged": "<?php echo $block->isCustomerLoggedIn(); ?>"
                        }
                    }
                }
            }
        }
        </script>
        <?php break; ?>

    <?php case 'other': ?>
        <?php echo $block->getChildHtml(); ?>
        <?php break; ?>

    <?php endswitch; ?>

app/code/Vendor/Theme/view/frontend/web/js/view/customer.js


define([
    'ko',
    'uiComponent',
    'Magento_Customer/js/customer-data',
    'mage/translate'
], function (ko, Component, customerData, $t) {
    'use strict';

    return Component.extend({

        message: {
            loggedMessage : $t('Welcome, %1!')
        },
        htmlLoggedMessage: ko.observable(),
        isLoggedIn: ko.observable(),
        customer: ko.observable({}),

        initialize: function() {
            this._super();
            if(this.isCustomerLogged != 0) {
                this.isLoggedIn(true);
            }
            this.checkCustomerLocalStorage();
        },

        /**
         * Check customer localstorage
         */
        checkCustomerLocalStorage: function () {
            var self = this;
            var time = setInterval(function () {
                self.customer = customerData.get('customer');
                if (localStorage["mage-cache-storage"] != '{}') {
                    clearInterval(time);
                }
                if (self.customer().fullname) {
                    var name = self.customer().fullname;
                    var message = self.message.loggedMessage.replace('%1', name);
                    self.htmlLoggedMessage(message);
                }
            }, 1000);
        }
    });
});

app/code/Vendor/Theme/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_Theme" setup_version="1.0.0"/>
</config>

app/code/Vendor/Theme/registration.php

<?php

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Vendor_Theme', __DIR__);

There are some notes:

  • We will override : Magento\Theme\Block\Html\Header
  • Create our own js: app/code/Vendor/Theme/view/frontend/web/js/view/customer.js. Don't need to override the js/view/customer.js default.
  • Use Magento\Framework\App\Http\Context to check customer context.

@magento-engcom-team magento-engcom-team added the Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed label Sep 11, 2017
@magento-engcom-team magento-engcom-team added Issue: Clear Description Gate 2 Passed. Manual verification of the issue description passed 2.1.x Issue: Ready for Work Gate 4. Acknowledged. Issue is added to backlog and ready for development Issue: Confirmed Gate 3 Passed. Manual verification of the issue completed. Issue is confirmed Reproduced on 2.1.x The issue has been reproduced on latest 2.1 release Reproduced on 2.2.x The issue has been reproduced on latest 2.2 release Reproduced on 2.3.x The issue has been reproduced on latest 2.3 release labels Oct 19, 2017
@magento-engcom-team
Copy link
Contributor

@ravinders-121, thank you for your report.
We've created internal ticket(s) MAGETWO-82290 to track progress on the issue.

@ghost
Copy link

ghost commented Dec 8, 2017

I've faced this issue after enabling varnish. Anyone solved this issue.

@martins-olekss
Copy link

Also facing same issue. Is there any additional information on this and on possible solutions ?

@sunilit42
Copy link
Contributor

@Theenluck any solution?

@magento-admin any solution with varnish?

@sunilit42
Copy link
Contributor

Hello @mimarcel

Thanks for your suggestion, but some case section is not loaded on logout and local storage same so i update little bit js code

app/code/Vendor/Theme/etc/frontend/di.xml


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Header" type="Vendor\Theme\Block\Html\Header"/>
</config>

app/code/Vendor/Theme/Block/Html/Header.php

<?php

namespace Vendor\Theme\Block\Html;

use Magento\Framework\View\Element\Template\Context;
use Magento\Theme\Block\Html\Header as HeaderBlock;
use Magento\Framework\App\Http\Context as CustomerContext;


class Header extends HeaderBlock
{
    /**
     * Current template name
     *
     * @var string
     */
    protected $_template = 'Vendor_Theme::html/header.phtml';

    /**
     * @var CustomerContext
     */
    protected $customerContext;

    /**
     * Header constructor.
     *
     * @param Context $context
     * @param CustomerContext $customerContext
     * @param array $data
     */
    public function __construct(
        Context $context,
        CustomerContext $customerContext,
        array $data = []
    ) {
        $this->customerContext = $customerContext;
        parent::__construct($context, $data);
    }

    /**
     * Check is Customer Logged In
     *
     * @return int
     */
    public function isCustomerLoggedIn()
    {
        $isLoggedIn = $this->customerContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH);
        return $isLoggedIn ? 1 : 0 ;
    }
}

app/code/Vendor/Theme/view/frontend/templates/html/header.phtml

<?php
// @codingStandardsIgnoreFile

/**
 * @var \Magento\Theme\Block\Html\Header $block
 */
$welcomeMessage = $block->getWelcome();
?>
<?php switch ($block->getShowPart()):
    case 'welcome': ?>
        <li class="greet welcome" data-bind="scope: 'customer'">
            <!-- ko if: isLoggedIn()  -->
            <span data-bind="text: htmlLoggedMessage()">
            </span>
            <!-- /ko -->
            <!-- ko ifnot: isLoggedIn()  -->
            <span data-bind="html:'<?=$block->escapeHtml($welcomeMessage) ?>'"></span>
            <!-- /ko -->
        </li>
        <script type="text/x-magento-init">
        {
            "*": {
                "Magento_Ui/js/core/app": {
                    "components": {
                        "customer": {
                            "component": "Vendor_Theme/js/view/customer",
                            "isCustomerLogged": "<?php echo $block->isCustomerLoggedIn(); ?>"
                        }
                    }
                }
            }
        }
        </script>
        <?php break; ?>

    <?php case 'other': ?>
        <?php echo $block->getChildHtml(); ?>
        <?php break; ?>

    <?php endswitch; ?>

app/code/Vendor/Theme/view/frontend/web/js/view/customer.js

define([
    'ko',
    'uiComponent',
    'Magento_Customer/js/customer-data',
    'mage/translate'
], function (ko, Component, customerData, $t) {
    'use strict';

    return Component.extend({

        message: {
            loggedMessage : $t('Welcome, %1!')
        },
        htmlLoggedMessage: ko.observable(),
        isLoggedIn: ko.observable(),
		isRun : ko.observable(),
        customer: ko.observable({}),

        initialize: function() {
			this.isRun(false);
            this._super();
            if(this.isCustomerLogged != 0) {
                this.isLoggedIn(true);
            }else{
				this.isLoggedIn(false);
			}
            this.checkCustomerLocalStorage();
        },

        /**
         * Check customer localstorage
         */
        checkCustomerLocalStorage: function () {
			var self = this;
			self.customer = customerData.get('customer');
			if(this.isLoggedIn()==false && self.customer().fullname!=undefined && this.isRun()==false){
			this.isRun(true);
			customerData.reload('customer');
			}
        }
    });
});

app/code/Vendor/Theme/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Vendor_Theme" setup_version="1.0.0"/>
</config>

app/code/Vendor/Theme/registration.php

<?php

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Vendor_Theme', __DIR__);

There are some notes:

We will override : Magento\Theme\Block\Html\Header
Create our own js: app/code/Vendor/Theme/view/frontend/web/js/view/customer.js. Don't need to override the js/view/customer.js default.
Use Magento\Framework\App\Http\Context to check customer context.

@zuber11
Copy link

zuber11 commented Dec 19, 2018

Open app/etc/env.php

and paste below code. This would allow you to fix everything.

'session' =>
array (
'save' => 'redis', // this should be radis instead of FILE
'redis' =>
array (
'host' => '', // Define correct host over here
'port' => '', // Define correct port over here
'password' => '', // Define correct password over here
'timeout' => '2.5',
'persistent_identifier' => '',
'database' => '2',
'compression_threshold' => '2048',
'compression_library' => 'gzip',
'log_level' => '3',
'max_concurrency' => '6',
'break_after_frontend' => '5',
'break_after_adminhtml' => '30',
'first_lifetime' => '600',
'bot_first_lifetime' => '60',
'bot_lifetime' => '7200',
'disable_locking' => '0',
'min_lifetime' => '60',
'max_lifetime' => '2592000'
)
),

@tuyennn
Copy link
Contributor

tuyennn commented Dec 28, 2018

Same issue experience on Magento 2 2.1.9 using Redis Cache.

@ghost
Copy link

ghost commented Jan 24, 2019

We are closing this issue, as we have new one here -> #20571

@angelflo
Copy link

angelflo commented Jan 8, 2021

Hi, I have exactly same problem with Magento 2.4.1 and varnish 6 installed.
Does someone have a real fix and/or explanation to solve it for this version ?

Thanks a lot

@nehaPanchal271297
Copy link

Hi I have faced same issue with Magento 2.4.6 and Varnish version 6.
Does someone have a real solution for this version?

Thanks a lot

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue: Clear Description Gate 2 Passed. Manual verification of the issue description passed Issue: Confirmed Gate 3 Passed. Manual verification of the issue completed. Issue is confirmed Issue: Format is not valid Gate 1 Failed. Automatic verification of issue format is failed Issue: Ready for Work Gate 4. Acknowledged. Issue is added to backlog and ready for development Reproduced on 2.1.x The issue has been reproduced on latest 2.1 release Reproduced on 2.2.x The issue has been reproduced on latest 2.2 release Reproduced on 2.3.x The issue has been reproduced on latest 2.3 release
Projects
None yet
Development

No branches or pull requests