【发布时间】:2011-12-05 16:30:31
【问题描述】:
当我将 Rails 应用部署到 Heroku 时,自动清除 Memcached 的最佳方法是什么?
我正在缓存主页,当我进行更改和重新部署时,页面会从缓存中提供,并且不会合并更新。
我想让这完全自动化。我不想在每次部署时都清除 heroku 控制台中的缓存。
谢谢!
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3 heroku memcached
当我将 Rails 应用部署到 Heroku 时,自动清除 Memcached 的最佳方法是什么?
我正在缓存主页,当我进行更改和重新部署时,页面会从缓存中提供,并且不会合并更新。
我想让这完全自动化。我不想在每次部署时都清除 heroku 控制台中的缓存。
谢谢!
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-3 heroku memcached
我使用 bash 脚本部署我的应用程序,该脚本自动执行 GitHub 和 Heroku 推送、数据库迁移、应用程序维护模式激活和缓存清除操作。
在这个脚本中,清除缓存的命令是:
heroku run --app YOUR_APP_NAME rails runner -e production Rails.cache.clear
这适用于带有 Heroku Toolbelt 软件包的 Celadon Cedar。我知道这不是基于 Rake 的解决方案,但它非常有效。
注意:确保将runner 命令的environment / -e 选项设置为production,否则它将在development 上执行。
编辑:几天以来,我在 Heroku 上遇到了这个命令的问题(Rails 3.2.21)。我没有时间检查问题的根源,但删除了-e production 成功了,所以如果命令不成功,请改为运行这个:
heroku run --app YOUR_APP_NAME rails runner Rails.cache.clear
【讨论】:
[在青瓷雪松堆上]
-- [2012 年 6 月 18 日更新 -- 这不再有效,看看我是否能找到其他解决方法]
我发现处理这些部署后挂钩的最简洁方法是锁定在 slug 编译期间已调用的 assets:precompile 任务。向asset_sync Gem 致敬:
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
我只是把它放在一个 lib/tasks/heroku_deploy.rake 文件中,它被很好地拾取。
【讨论】:
assets:precompile:digest,但即使你 enahance 那个任务,它只会导致预编译失败。
lib/tasks/heroku_deploy.rake 会自动调用吗?
我最终做的是创建一个新的 rake 任务,该任务部署到 heroku,然后清除缓存。我创建了一个 deploy.rake 文件,就是这样:
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
现在,我不用输入 git push heroku,而是输入 rake deploy:production。
【讨论】:
2013 年 1 月 25 日:这适用于在 Cedar 上的 Ruby 1.9.3 上运行的 Rails 3.2.11 应用程序
在您的 Gemfile 中添加以下行以强制 ruby 1.9.3:
ruby '1.9.3'
使用以下内容创建一个名为 lib/tasks/clear_cache.rake 的文件:
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
最后,我还建议在您的应用上运行 heroku labs:enable user-env-compile,以便您可以在预编译过程中使用它的环境。
【讨论】:
除了您可以在“应用程序启动”上运行的应用程序中执行的任何操作之外,您还可以使用会命中 URL 的 heroku 部署挂钩 (http://devcenter.heroku.com/articles/deploy-hooks#http_post_hook)在您的应用程序中清除缓存
【讨论】:
我添加了config/initializers/expire_cache.rb
ActionController::Base.expire_page '/'
工作甜蜜!
【讨论】:
由于 heroku gem 已被弃用,Solomons 的更新版本非常优雅的答案是将以下代码保存在 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
然后在命令行中输入rake deploy:production 而不是git push heroku master。
要清除缓存,您可以运行 rake cache:clear
【讨论】:
我喜欢使用的解决方案如下:
首先,我实现了一个 deploy_hook 操作,用于查找我为每个应用设置不同的参数。通常我只是在“家庭”或“公共”控制器上执行此操作,因为它不需要那么多代码。
### routes.rb ###
post 'deploy_hook' => 'home#deploy'
### home_controller.rb ###
def deploy_hook
Rails.cache.clear if params[:secret] == "a3ad3d3"
end
而且,我只是告诉 heroku 设置一个部署挂钩,以便在我部署时发布到该操作!
heroku addons:add deployhooks:http \
--url=http://example.com/deploy_hook?secret=a3ad3d3
现在,每次我部署时,heroku 都会向站点发送一个 HTTP 帖子,让我知道部署工作正常。
对我来说就像一个魅力。当然,秘密令牌不是“高安全性”,如果有一个很好的攻击媒介可以在缓存被清除的情况下关闭您的站点,则不应使用此令牌。但是,老实说,如果该站点对攻击至关重要,那么就不要在 Heroku 上托管它!但是,如果您想稍微提高安全性,那么您可以使用 Heroku 配置变量,而源代码中根本没有“令牌”。
希望人们觉得这很有用。
【讨论】:
我也遇到了这个问题,但想坚持使用 git 部署,而不需要额外的脚本作为包装器。
所以我的方法是在 slug 生成期间使用标记当前预编译的 uuid 编写一个文件。这是在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
另一个是一个初始化器,它根据缓存的版本检查这个 id。如果它们不同,则已经进行了另一次预编译,并且缓存将失效。
因此,无论应用程序启动或关闭的频率或工作程序将分布在多少个节点上都无关紧要,因为 slug 生成只发生一次。
# /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
我需要使用随机 ID,因为据我所知,无法获取 git 哈希或任何其他有用的 ID。也许是ENV[REQUEST_ID],但这也是一个随机 ID。
uuid 的好处是,它现在也独立于 heroku。
【讨论】: