Pregunta

Ya tengo un deploy.rb que puede implementar mi aplicación en mi servidor de producción.

Mi aplicación contiene una tarea de rastrillo personalizada (un archivo .rake en el directorio lib / task).

Me gustaría crear una tarea de límite que ejecute remotamente esa tarea de rastrillo.

¿Fue útil?

Solución 2

run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production")

Lo encontré con Google - http : //ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

El RAILS_ENV = production fue un problema: al principio no lo pensé y no pude entender por qué la tarea no estaba haciendo nada.

Otros consejos

Un poco más explícito, en su \ config \ deploy.rb , agregue fuera 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

... un par de años después ...

Eche un vistazo al complemento de rieles de capistrano, puede verlo en https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 puede verse algo 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 (ejecute cualquier tarea de rastrillo)

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

Ejemplo de uso: puesta en escena de tope " invoke [db: migrate] "

Tenga en cuenta que deploy: set_rails_env requiere proviene de la gema capistrano-rails

Usar invocaciones de rastrillo estilo Capistrano

Hay una forma común que simplemente "funcionará" con requiere 'bundler / capistrano' y otras extensiones que modifican rake. Esto también funcionará con entornos de preproducción si está utilizando etapas múltiples. ¿La esencia? Use config vars si puede.

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

Utilice la capistrano-rake gem

Simplemente instale la gema sin meterse con recetas personalizadas de capistrano y ejecute las tareas de rastrillo deseadas en servidores remotos como este:

cap production invoke:rake TASK=my:rake_task

Divulgación completa: lo escribí

Personalmente uso en producción un método auxiliar 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 rastrillo similar al uso del método de ejecución (comando).


NOTA: es similar a lo que Duque propuso, pero yo:

  • use latest_release en lugar de current_release: según mi experiencia, es más de lo que espera al ejecutar un comando rake;
  • siga la convención de nomenclatura de Rake y Capistrano (en lugar de: cmd - > task and rake - > run_rake)
  • no establezca RAILS_ENV = # {rails_env} porque el lugar correcto para configurarlo es la variable default_run_options. Por ejemplo, default_run_options [: env] = {'RAILS_ENV' = > 'producción'} # - > SECO!

Hay una gema interesante capa que hace que tus tareas de rastrillo estén disponibles como tareas de Capistrano, para que puedas ejecutarlas remotamente cape está bien documentado, pero aquí hay una breve descripción de cómo configurar i.

Después de instalar la gema, simplemente agregue esto 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 de forma local o remota a través de cap .

Como una ventaja adicional, cape le permite configurar cómo desea ejecutar su tarea de rake local y remotamente (no más bundle exec rake ), solo 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 contenedor simple alrededor 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 rastrillo de esta manera:

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 cap production " invoke [task_name] "

La mayor parte es de respuesta anterior con una mejora menor para ejecutar cualquier tarea de rastrillo desde capistrano

Ejecuta cualquier tarea de rastrillo 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 <rake_task_name>", :env => {'RAILS_ENV' => rails_env})

Más información: Capistrano Run

Si desea poder pasar varios argumentos, intente esto (según 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

Entonces puede ejecutar una tarea como esta: cap producción 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 modo de depuración. Estas semas a h

SSHKit.config.output_verbosity = Logger::DEBUG

Material de tapa

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: textimple integrado en el sshkit, pero no es una mala manera de invocar tareas personalizadas. Oh, esto no funciona con la versión más nueva de sshkit gem. Sé que funciona con 1.7.1. Digo esto porque la rama maestra 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top