Ya tengo un deploy.rb que puede implementar mi aplicación en mi servidor de producción.
Mi aplicación contiene una tarea de rake personalizada (un archivo .rake en el directorio lib / tasks).
Me gustaría crear una tarea de límite que ejecute de forma remota esa tarea de rake.
Un poco más explícito, en su \config\deploy.rb
, agregue afuera de cualquier tarea o espacio de nombres:
namespace :rake do desc "Run a task on a remote server." # run like: cap staging rake:invoke task=a_certain_task task :invoke do run("cd #{deploy_to}/current; /usr/bin/env rake #{ENV['task']} RAILS_ENV=#{rails_env}") end end
Luego, desde /rails_root/
, puede ejecutar:
cap staging rake:invoke task=rebuild_table_abc
run("cd #{deploy_to}/current && /usr/bin/env rake `` RAILS_ENV=production")
Lo encontré con Google – http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/
La RAILS_ENV=production
fue una sorpresa. Al principio no pensé en eso y no pude entender por qué la tarea no estaba haciendo nada.
… un par de años después …
Eche un vistazo al plugin de capistrano’s rails, que puede ver en https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 y puede verse más o menos así:
desc 'Runs rake db:migrate if migrations are set' task :migrate => [:set_rails_env] do on primary fetch(:migration_role) do within release_path do with rails_env: fetch(:rails_env) do execute :rake, "db:migrate" end end end end
Versión genérica de Capistrano 3 (ejecutar cualquier tarea de rake)
Construyendo una versión genérica de la respuesta de Mirek Rusin:
desc 'Invoke a rake command on the remote server' task :invoke, [:command] => 'deploy:set_rails_env' do |task, args| on primary(:app) do within current_path do with :rails_env => fetch(:rails_env) do rake args[:command] end end end end
Uso de ejemplo: cap staging "invoke[db:migrate]"
Tenga en cuenta que deploy:set_rails_env
requires proviene de la gem capistrano-rails
Hay una forma común de “solo funcionar” con require 'bundler/capistrano'
y otras extensiones que modifican el rake. Esto también funcionará con entornos de preproducción si está utilizando varias etapas. ¿La esencia? Usa config vars si puedes.
desc "Run the super-awesome rake task" task :super_awesome do rake = fetch(:rake, 'rake') rails_env = fetch(:rails_env, 'production') run "cd '#{current_path}' && #{rake} super_awesome RAILS_ENV=#{rails_env}" end
capistrano-rake
Simplemente instale la gem sin jugar con las recetas personalizadas de capistrano y ejecute las tareas de rake deseadas en servidores remotos como este:
cap production invoke:rake TASK=my:rake_task
Divulgación completa: lo escribí
Yo personalmente uso en producción un método de ayuda como este:
def run_rake(task, options={}, &block) command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}" run(command, options, &block) end
Eso permite ejecutar una tarea de rake similar a usar el método de ejecución (comando).
NOTA: Es similar a lo que Duke propuso, pero yo:
Hay una capa de gems interesante que hace que sus tareas de rake estén disponibles como tareas de Capistrano, por lo que puede ejecutarlas de forma remota. cape
está bien documentada, pero aquí hay una breve descripción de cómo configurar i.
Después de instalar la gem, simplemente agréguela a su archivo config/deploy.rb
.
# config/deploy.rb require 'cape' Cape do # Create Capistrano recipes for all Rake tasks. mirror_rake_tasks end
Ahora puede ejecutar todas sus tareas de rake
local o remota a través de cap
.
Como una ventaja adicional, cape
permite establecer cómo desea ejecutar su tarea de rake de forma local y remota (no más bundle exec rake
), simplemente agregue esto a su archivo config/deploy.rb
:
# Configure Cape to execute Rake via Bundler, both locally and remotely. Cape.local_rake_executable = '/usr/bin/env bundle exec rake' Cape.remote_rake_executable = '/usr/bin/env bundle exec rake'
namespace :rake_task do task :invoke do if ENV['COMMAND'].to_s.strip == '' puts "USAGE: cap rake_task:invoke COMMAND='db:migrate'" else run "cd #{current_path} && RAILS_ENV=production rake #{ENV['COMMAND']}" end end end
Esto es lo que puse en mi deploy.rb para simplificar la ejecución de tareas de rake. Es un simple contenedor del método run () de capistrano.
def rake(cmd, options={}, &block) command = "cd #{current_release} && /usr/bin/env bundle exec rake #{cmd} RAILS_ENV=#{rails_env}" run(command, options, &block) end
Luego, simplemente ejecuto cualquier tarea de rake así:
rake 'app:compile:jammit'
Esto funcionó para mí:
task :invoke, :command do |task, args| on roles(:app) do within current_path do with rails_env: fetch(:rails_env) do execute :rake, args[:command] end end end end
Luego simplemente ejecute la cap production "invoke[task_name]"
La mayor parte es de la respuesta anterior con una mejora menor para ejecutar cualquier tarea de rastrear desde capistrano
Ejecuta cualquier tarea de rastrear desde capistrano
$ cap rake -s rake_task=$rake_task # Capfile task :rake do rake = fetch(:rake, 'rake') rails_env = fetch(:rails_env, 'production') run "cd '#{current_path}' && #{rake} #{rake_task} RAILS_ENV=#{rails_env}" end
Esto también funciona:
run("cd #{release_path}/current && /usr/bin/rake ", :env => {'RAILS_ENV' => rails_env})
Más información: Capistrano Run
Si quieres poder pasar múltiples argumentos, prueba esto (basado en la respuesta de marinosbern):
task :invoke, [:command] => 'deploy:set_rails_env' do |task, args| on primary(:app) do within current_path do with :rails_env => fetch(:rails_env) do execute :rake, "#{args.command}[#{args.extras.join(",")}]" end end end end
Luego puede ejecutar una tarea como esta: cap production invoke["task","arg1","arg2"]
Así que he estado trabajando en esto. parece que funciona bien. Sin embargo, necesita un formateador para aprovechar realmente el código.
Si no desea utilizar un formateador, simplemente configure el nivel de registro en el modo de depuración. Estos semas a h
SSHKit.config.output_verbosity = Logger::DEBUG
namespace :invoke do desc 'Run a bash task on a remote server. cap environment invoke:bash[\'ls -la\'] ' task :bash, :execute do |_task, args| on roles(:app), in: :sequence do SSHKit.config.format = :supersimple execute args[:execute] end end desc 'Run a rake task on a remote server. cap environment invoke:rake[\'db:migrate\'] ' task :rake, :task do |_task, args| on primary :app do within current_path do with rails_env: fetch(:rails_env) do SSHKit.config.format = :supersimple rake args[:task] end end end end end
Este es el formateador que construí para trabajar con el código anterior. Se basa en: text simple integrado en el sshkit, pero no es una mala manera de invocar tareas personalizadas. Oh, esto no funciona con la última versión de sshkit gem. Sé que funciona con 1.7.1. Digo esto porque la twig principal ha cambiado los métodos SSHKit :: Command que están disponibles.
module SSHKit module Formatter class SuperSimple < SSHKit::Formatter::Abstract def write(obj) case obj when SSHKit::Command then write_command(obj) when SSHKit::LogMessage then write_log_message(obj) end end alias :<< :write private def write_command(command) unless command.started? && SSHKit.config.output_verbosity == Logger::DEBUG original_output << "Running #{String(command)} #{command.host.user ? "as #{command.host.user}@" : "on "}#{command.host}\n" if SSHKit.config.output_verbosity == Logger::DEBUG original_output << "Command: #{command.to_command}" + "\n" end end unless command.stdout.empty? command.stdout.lines.each do |line| original_output << line original_output << "\n" unless line[-1] == "\n" end end unless command.stderr.empty? command.stderr.lines.each do |line| original_output << line original_output << "\n" unless line[-1] == "\n" end end end def write_log_message(log_message) original_output << log_message.to_s + "\n" end end end end