capistrano-magento2 icon indicating copy to clipboard operation
capistrano-magento2 copied to clipboard

Cached data from current release causes new release to fail with redis caching

Open PascalBrouwers opened this issue 5 years ago • 6 comments

Similar issue to: https://github.com/davidalger/capistrano-magento2/issues/138

When running magento:maintenance:enable the redis cache is not correct. You fixed it by flushing before app:config:import, but it should have done a cache flush after the magento:maintenance:enable in the release_path

issue with cache:

16:47:12       
16:47:12       Maintenance mode usage will be enforced per :magento_deploy_maintenance (setting is true)
16:47:12 07:05 magento:maintenance:enable
16:47:12       01 /usr/bin/php72 -f bin/magento -- maintenance:enable
16:47:13       01 Enabled maintenance mode
16:47:13     ✔ 01 xxx@xxx 0.865s
16:47:13       01 
16:47:13       01 In ClassReader.php line 19:
16:47:13       01                                                     
16:47:13       01   Class Vertex\Tax\Model\Cache\Type does not exist  
16:47:13       01                                                     
16:47:13       01 
16:47:13       01 maintenance:enable [--ip IP] [--magento-init-params MAGENTO-INIT-PARAMS]

To fix it I added the following to override it:

Rake::Task["magento:maintenance:enable"].clear

namespace :magento do
  namespace :maintenance do
    task :enable do
      on release_roles :all do
        within release_path do
          execute :magento, 'cache:flush'
          execute :magento, 'maintenance:enable'
          execute :magento, 'cache:flush'
        end
      end
    end
  end
end

The issue is that a cache:flush needs to be done after the maintenance:enable, because then it does a maintenance:enable in the current_path (https://github.com/davidalger/capistrano-magento2/blob/3d32c7d654bd9221f67e20c27fc4e62503bdd73d/lib/capistrano/tasks/deploy.rake#L74)

PascalBrouwers avatar Sep 01 '20 09:09 PascalBrouwers

We have also experienced this. But we have seen that capistrano-magento2 in the end just invokes magento:setup:di:compile, so it didn't look like the element to blame:

https://github.com/davidalger/capistrano-magento2/blob/3d32c7d654bd9221f67e20c27fc4e62503bdd73d/lib/capistrano/tasks/deploy.rake#L57

We still have some issues in our production environment during production releases - where classes are not generated. But seeing your issue @PascalBrouwers made us thought of it to tackle it better than manually copying the generated files from the staging server to production 😅

Maybe capistrano-magento2 could force Magento to ignore the Redis cache while preparing the 2nd release?

zetxek avatar Sep 01 '20 09:09 zetxek

That's not possible, but I should make sure that running commands between release_path and current_path the cache should be flushed.

PascalBrouwers avatar Sep 01 '20 09:09 PascalBrouwers

Small update: you also need to fix the autoloader because that is cached too. So run this too: invoke!('magento:composer:install') if fetch(:magento_deploy_composer)

PascalBrouwers avatar Oct 09 '20 10:10 PascalBrouwers

Trying to get a fail-safe method for this but it feels like there isn't one.

As soon as you flush the redis cache there is the possibility that a visitor is on the site and trigger the redis cache for the current release, while you were trying to fill it with the release_path. There is the option to set the maintenance flag, but that would mean a long downtime.

PascalBrouwers avatar Nov 13 '20 08:11 PascalBrouwers

Also an issue when running php 7.2 / 7.3 in your current release and the latest release need php 7.4 Running composer install in both directories isn't going to work with the same php version.

PascalBrouwers avatar Nov 16 '20 14:11 PascalBrouwers

Decided to go with using a different cache prefix for each deployment. This way generated files and other caches don't interfere with each other during a deploy for a site that has allot of visitors. Because this runs before composer, if also fixes the issue with the classmap cache.

after "deploy:symlink:linked_files", "set_cache_prefix"
task :set_cache_prefix do
  on release_roles :all do
    within release_path do
      unless test %Q[#{SSHKit.config.command_map[:php]} -r '
          $cfg = include "#{shared_path}/app/etc/env.php";
          exit((int)!isset($cfg["cache"]["frontend"]["default"]["id_prefix"]));
        ']
        # generate a new prefix
        version = '100_'
      else
        # get the current prefix
        version = capture %Q[#{SSHKit.config.command_map[:php]} -r '
            $cfg = include "#{shared_path}/app/etc/env.php";
            echo(($cfg["cache"]["frontend"]["default"]["id_prefix"]));
        ']
      end

      # convert prefix to a number and increment it
      version = version.gsub("_", "")
      versionNumber = version.to_i
      newVersionNumber = versionNumber + 1
      set :newVersionNumber, newVersionNumber

      # copy the file as a normal file in the next release
      execute :rm, "-rf #{release_path}/app/etc/env.php"
      execute :cp, "-rf #{shared_path}/app/etc/env.php #{release_path}/app/etc/env.php"

      execute %Q[#{SSHKit.config.command_map[:php]} -r '
        $cfg = include "#{release_path}/app/etc/env.php";
        $cfg["cache"]["frontend"]["default"]["id_prefix"] = "#{fetch(:newVersionNumber)}_";
        $out = "<?php return " . var_export($cfg, true) . ";"
        file_put_contents("#{release_path}/app/etc/env.php", $out);
        ']

      # save new env file to shared dir
      execute :rm, "-rf #{shared_path}/app/etc/env.php"
      execute :cp, "-rf #{release_path}/app/etc/env.php #{shared_path}/app/etc/env.php"
    end
  end
end

Works when env.php does not have a cache prefix yet. Also Magento fixes the array( syntax with a short syntax [ during deployment by itself. @davidalger is this an idea to include it?

PascalBrouwers avatar Jan 28 '21 16:01 PascalBrouwers