简体   繁体   中英

Clear Memcached on Heroku Deploy

What is the best way to automatically clear Memcached when I deploy my rails app to Heroku?

I'm caching the home page, and when I make changes and redeploy, the page is served from the cache, and the updates aren't incorporated.

I want to have this be totally automated. I don't want to have to clear the cache in the heroku console each time I deploy.

Thanks!

I deploy my applications using a bash script that automates GitHub & Heroku push, database migration, application maintenance mode activation and cache clearing action.

In this script, the command to clear the cache is :

heroku run --app YOUR_APP_NAME rails runner -e production Rails.cache.clear

This works with Celadon Cedar with the Heroku Toolbelt package. I know this is not a Rake-based solution however it's quite efficient.

Note : be sure you set the environment / -e option of the runner command to production as it will be executed on the development one otherwise.

Edit : I have experienced issues with this command on Heroku since a few days (Rails 3.2.21). I did not have time to check the origin the issue but removing the -e production did the trick, so if the command does not succeed, please run this one instead :

heroku run --app YOUR_APP_NAME rails runner Rails.cache.clear

[On the Celadon Cedar Stack]

-- [Update 18 June 2012 -- this no longer works, will see if I can find another workaround]

The cleanest way I have found to handle these post-deploy hooks is to latch onto the assets:precompile task that is already called during slug compilation. With a nod to asset_sync Gem for the idea:

Rake::Task["assets:precompile"].enhance do
  # How to invoke a task that exists elsewhere
  # Rake::Task["assets:environment"].invoke if Rake::Task.task_defined?("assets:environment")

  # Clear cache on deploy
  print "Clearing the rails memcached cache\n"
  Rails.cache.clear
end

I just put this in a lib/tasks/heroku_deploy.rake file and it gets picked up nicely.

What I ended up doing was creating a new rake task that deployed to heroku and then cleared the cache. I created a deploy.rake file and this is it:

namespace :deploy do

    task :production do
        puts "deploying to production"
        system "git push heroku"
        puts "clearing cache"
        system "heroku console Rails.cache.clear"
        puts "done"
    end

end

Now, instead of typing git push heroku, I just type rake deploy:production.

25 Jan 2013: this is works for a Rails 3.2.11 app running on Ruby 1.9.3 on Cedar

In your Gemfile add the following line to force ruby 1.9.3:

ruby '1.9.3'

Create a file named lib/tasks/clear_cache.rake with this content:

if Rake::Task.task_defined?("assets:precompile:nondigest")
  Rake::Task["assets:precompile:nondigest"].enhance do
    Rails.cache.clear
  end
else
  Rake::Task["assets:precompile"].enhance do
    # rails 3.1.1 will clear out Rails.application.config if the env vars
    # RAILS_GROUP and RAILS_ENV are not defined. We need to reload the
    # assets environment in this case.
    # Rake::Task["assets:environment"].invoke if Rake::Task.task_defined?("assets:environment")
    Rails.cache.clear
  end
end

Finally, I also recommend running heroku labs:enable user-env-compile on your app so that its environment is available to you as part of the precompilation.

除了在“应用程序启动”上运行的应用程序内部可以执行的任何操作之外,您可以使用将在应用程序中命中URL的heroku部署挂钩(http://devcenter.heroku.com/articles/deploy-hooks#http_post_hook)清除缓存

I've added config/initializers/expire_cache.rb with

ActionController::Base.expire_page '/'

Works sweet!

Since the heroku gem is deprecated, an updated version of Solomons very elegant answer would be to save the following code in lib/tasks/heroku_deploy.rake :

namespace :deploy do
    task :production do
        puts "deploying to production"
        system "git push heroku"
        puts "clearing cache"
        system "heroku run rake cache:clear"
        puts "done"
    end
end

namespace :cache do
  desc "Clears Rails cache"
  task :clear => :environment do
    Rails.cache.clear
  end
end

then instead of git push heroku master you type rake deploy:production in command line. To just clear the cache you can run rake cache:clear

The solution I like to use is the following:

First, I implement a deploy_hook action that looks for a parameter that I set differently for each app. Typically I just do this on the on the "home" or "public" controller, since it doesn't take that much code.

### routes.rb ###

post 'deploy_hook' => 'home#deploy'

### home_controller.rb ###

def deploy_hook
  Rails.cache.clear if params[:secret] == "a3ad3d3"
end

And, I simply tell heroku to setup a deploy hook to post to that action whenever I deploy!

heroku addons:add deployhooks:http \
   --url=http://example.com/deploy_hook?secret=a3ad3d3

Now, everytime that I deploy, heroku will do an HTTP post back to the site to let me know that the deploy worked just fine.

Works like a charm for me. Of course, the secret token not "high security" and this shouldn't be used if there were a good attack vector for taking your site down if caches were cleared. But, honestly, if the site is that critical to attack, then don't host it on Heroku! However, if you wanted to increase the security a bit, then you could use a Heroku configuration variable and not have the 'token' in the source code at all.

Hope people find this useful.

I just had this problem as well but wanted to stick to the git deployment without an additional script as a wrapper.

So my approach is to write a file during slug generation with an uuid that marks the current precompilation. This is impelmented as a hook in assets:precompile .

# /lib/tasks/store_asset_cacheversion.rake
# add uuidtools to Gemfile

require "uuidtools"

def storeCacheVersion
  cacheversion = UUIDTools::UUID.random_create
  File.open(".cacheversion", "w") { |file| file.write(cacheversion) }
end

Rake::Task["assets:precompile"].enhance do
  puts "Storing git hash in file for cache invalidation (assets:precompile)\n"
  storeCacheVersion
end

Rake::Task["assets:precompile:nondigest"].enhance do
  puts "Storing git hash in file for cache invalidation (assets:precompile:nondigest)\n"
  storeCacheVersion
end

The other is an initializer that checks this id against the cached version. If they differ, there has been another precompilation and the cache will be invalidated.

So it dosen't matter how often the application spins up or down or on how many nodes the worker will be distributed, because the slug generation just happens once.

# /config/initializers/00_asset_cache_check.rb

currenthash = File.read ".cacheversion"
cachehash   = Rails.cache.read "cacheversion"

puts "Checking cache version: #{cachehash} against slug version: #{currenthash}\n"

if currenthash != cachehash
  puts "flushing cache\n"
  Rails.cache.clear
  Rails.cache.write "cacheversion", currenthash
else
  puts "cache ok\n"
end

I needed to use a random ID because there is as far as I know no way of getting the git hash or any other useful id. Perhaps the ENV[REQUEST_ID] but this is an random ID as well.

The good thing about the uuid is, that it is now independent from heroku as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM