Bagaimana cara menjalankan tugas rake dari Capistrano?


105

Saya sudah memiliki deploy.rb yang dapat menerapkan aplikasi saya di server produksi saya.

Aplikasi saya berisi tugas rake khusus (file .rake di direktori lib / tugas).

Saya ingin membuat tugas batas yang akan menjalankan tugas menyapu itu dari jarak jauh.


2
Bisakah seseorang menjelaskan pro / kontra menggunakan #{rake}variabel capistrano sendiri ? Sepertinya itu tidak selalu merupakan pilihan terbaik.
lulalala

Jawaban:


59

Sedikit lebih eksplisit, di Anda \config\deploy.rb, tambahkan di luar tugas atau namespace apa pun:

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

Kemudian, dari /rails_root/, Anda dapat menjalankan:

cap staging rake:invoke task=rebuild_table_abc

1
lebih baik menggunakan / usr / bin / env rake sehingga rvm setup akan mengambil rake yang benar.
DGM

8
Dengan 'bundle exec' jika tersedia
Bogdan Gusiev

44

... beberapa tahun kemudian ...

Lihatlah plugin rel capistrano, Anda dapat melihat di https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14 itu bisa terlihat seperti:

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

3
Ini hanya untuk capistrano v3.
phillbaker

Banyak membantu. Terima kasih! @Mirek Rusin
Nishant Shrivastava

balasan lainnya, penggunaan itu runakan berfungsi pada capistrano hingga versi 2. dari versi 3 ini adalah cara yang harus dilakukan.
Don Giulio

44

Capistrano 3 Generic Version (menjalankan tugas menyapu)

Membangun versi generik dari jawaban 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

Contoh penggunaan: cap staging "invoke[db:migrate]"

Perhatikan bahwa kebutuhan deploy:set_rails_envberasal dari permata capistrano-rails


1
Ini hanya mendukung satu argumen, jika Anda menggantinya rake args[:command] dengan execute :rake, "#{args.command}[#{args.extras.join(",")}]" Anda dapat menjalankan tugas dengan beberapa argumen seperti: cap production invoke["task","arg1","arg2"]
Robin Clowers

1
@ Robin Clowers Anda dapat memberikan beberapa argumen, mis cap staging invoke['task[arg1\,arg2]']. Saya lebih suka pendekatan ini daripada yang Anda sebutkan karena ini mencerminkan permintaan rake yang sebenarnya. Dengan pendekatan ini Anda juga dapat rantai beberapa tugas, yang sering berguna: cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']. Berfungsi untuk rake 10.2.0 atau yang lebih baru
marinosb

ini bagus - saya ingin mencatat, Anda perlu memasukkan: app sebagai salah satu peran server Anda.
lfender6445

Rupanya ini perlu "memanggil [db: migrate]" ... Koreksi dilakukan.
Abram

@Abram dengan perintah yang Anda sarankan saya mendapatkan "Tidak tahu bagaimana membangun tugas 'memanggil"
dc10

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

Menemukannya dengan Google - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

Itu RAILS_ENV=productionadalah gotcha - saya tidak memikirkannya pada awalnya dan tidak tahu mengapa tugas itu tidak melakukan apa-apa.


2
Perbaikan kecil: jika Anda mengganti titik koma dengan && maka pernyataan kedua (menjalankan tugas rake) tidak akan berjalan jika pernyataan pertama (mengubah direktori) gagal.
Teflon Ted

2
Ini tidak akan berfungsi jika Anda menerapkan ke beberapa server. Ini akan menjalankan tugas menyapu beberapa kali.
Mark Redding

4
orang harus benar-benar menghormati pengaturan penggaruk capistrano"cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"
kares

@ Mark Redding: Bisakah Anda menempatkan salah satu server dalam perannya sendiri untuk tugas menyapu dan membatasi tugas capistrano Anda agar hanya berjalan di server dengan peran itu?
mj1531

Saya melakukan sesuatu di mana saya membuat tugas di deploy.rb saya. Tugas itu memiliki: peran =>: db di atasnya sehingga hanya akan dijalankan di server yang sama yang saya definisikan sebagai primer saya untuk db: migrate.
Mark Redding

20

Gunakan doa rake gaya Capistrano

Ada cara umum yang akan "berfungsi" dengan require 'bundler/capistrano'dan ekstensi lain yang mengubah penggaruk. Ini juga akan bekerja dengan lingkungan praproduksi jika Anda menggunakan multistage. Intinya? Gunakan config vars jika Anda bisa.

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

2
Ini adalah solusi terbaik, menggunakan nilai capistrano jika tersedia
loopj

2
Mungkin perlu ditambahkan bahwa jika tugas Anda memiliki namespace (yaitu tidak ditentukan dalam namespace tingkat atas), Anda mungkin harus menggunakan top.runalih-alih hanyarun
dolzenko

Terima kasih @dolzenko. Baru saja menemukan dokumen untuk topmetode tersebut . Dalam kasus di mana kita telah mendefinisikan rundi namespace yang sama, top.rundiperlukan, jika tidak, ia masih harus menemukan tingkat atas runbahkan di mana tugas diberi ruang nama. Apakah saya melewatkan sesuatu? Apa yang terjadi dalam kasus Anda?
captainpete

1
Saya jelas tidak memiliki metode run yang ditentukan di namespace yang sama, jadi tidak yakin mengapa saya membutuhkannya. Bagaimanapun, Capistrano 2.0 adalah sejarah dan versi berikutnya adalah berbasis Rake (semoga membuat segalanya lebih dapat diprediksi)
dolzenko

16

Gunakan capistrano-rakepermata itu

Cukup instal permata tanpa mengotak-atik resep capistrano khusus dan jalankan tugas rake yang diinginkan di server jarak jauh seperti ini:

cap production invoke:rake TASK=my:rake_task

Pengungkapan Penuh: Saya menulisnya


7

Saya pribadi menggunakan metode pembantu dalam produksi seperti ini:

def run_rake(task, options={}, &block)
  command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}"
  run(command, options, &block)
end

Itu memungkinkan untuk menjalankan tugas rake mirip dengan menggunakan metode run (perintah).


CATATAN: Ini mirip dengan apa yang diusulkan Duke , tetapi saya:

  • gunakan latest_release alih-alih current_release - dari pengalaman saya, ini lebih seperti yang Anda harapkan saat menjalankan perintah rake;
  • ikuti konvensi penamaan Rake dan Capistrano (sebagai ganti: cmd -> task and rake -> run_rake)
  • jangan setel RAILS_ENV = # {rails_env} karena tempat yang tepat untuk menyetelnya adalah variabel default_run_options. Misalnya default_run_options [: env] = {'RAILS_ENV' => 'production'} # -> KERING!

5

Ada jubah permata menarik yang membuat tugas penggaruk Anda tersedia sebagai tugas Capistrano, sehingga Anda dapat menjalankannya dari jarak jauh. capedidokumentasikan dengan baik, tetapi berikut adalah ikhtisar singkat tentang cara menyiapkan saya.

Setelah menginstal permata, cukup tambahkan ini ke config/deploy.rbfile Anda .

# config/deploy.rb
require 'cape'
Cape do
  # Create Capistrano recipes for all Rake tasks.
  mirror_rake_tasks
end

Sekarang, Anda dapat menjalankan semua raketugas Anda secara lokal atau jarak jauh cap.

Sebagai bonus tambahan, capememungkinkan Anda mengatur bagaimana Anda ingin menjalankan tugas rake Anda secara lokal dan jarak jauh (tidak lebih bundle exec rake), cukup tambahkan ini ke config/deploy.rbfile Anda :

# 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'

Catatan: hanya berfungsi untuk Capistrano v2.x. Tidak kompatibel dengan Capistrano v3.
nayiaw

3
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 

1
Baik. Mengubahnya dari RAILS_ENV=productionmenjadi RAILS_ENV=#{rails_env}memungkinkannya berfungsi di server pementasan saya juga.
evanrmurphy

2

Inilah yang saya masukkan ke deploy.rb saya untuk menyederhanakan menjalankan tugas rake. Ini adalah pembungkus sederhana di sekitar metode run () 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

Lalu saya hanya menjalankan tugas menyapu seperti ini:

rake 'app:compile:jammit'

konflik ini karena capistrano mendefinisikan variabel penggaruknya sendiri (digunakan untuk menentukan penggaruk mana yang akan digunakan) dan dengan demikian memecah tanda terima yang dibangun misalnya yang mengompilasi aset
Michael

2

Ini berhasil untuk saya:

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

Lalu lari saja cap production "invoke[task_name]"


1

Sebagian besar berasal dari jawaban di atas dengan sedikit peningkatan untuk menjalankan tugas menyapu dari capistrano

Jalankan tugas menyapu apa pun dari 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

1

Ini juga berfungsi:

run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env})

Info lebih lanjut: Capistrano Run


1
{deploy_to} / current tidak akan berfungsi di sini. Tautan simbolis tidak berubah. Jika Anda memperbarui tugas rake, ini akan menjalankan kode lama. Pertimbangkan untuk menggunakan {release_path} sebagai gantinya.
Mark Redding

info lebih lanjut adalah spam?
hcarreras

1

Jika Anda ingin dapat memberikan banyak argumen, coba ini (berdasarkan jawaban 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

Kemudian Anda dapat menjalankan tugas seperti ini: cap production invoke["task","arg1","arg2"]


0

Jadi saya telah mengerjakan ini. itu jahitan untuk bekerja dengan baik. Namun, Anda memerlukan pemformat untuk benar-benar memanfaatkan kode tersebut.

Jika Anda tidak ingin menggunakan pemformat, cukup setel level log ke mode debug. Semas ini untuk h

SSHKit.config.output_verbosity = Logger::DEBUG

Barang Topi

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

Ini adalah pemformat yang saya buat untuk bekerja dengan kode di atas. Ini didasarkan pada: teks sederhana yang dibangun ke dalam sshkit tetapi itu bukan cara yang buruk untuk menjalankan tugas khusus. Oh ini banyak yang tidak berfungsi dengan versi terbaru dari permata sshkit. Saya tahu ini berfungsi dengan 1.7.1. Saya mengatakan ini karena cabang master telah mengubah metode SSHKit :: Command yang tersedia.

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

0

Jawaban sebelumnya tidak membantu saya dan saya menemukan ini: Dari http://kenglish.co/run-rake-tasks-on-the-server-with-capistrano-3-and-rbenv/

namespace :deploy do
  # ....
  # @example
  #   bundle exec cap uat deploy:invoke task=users:update_defaults
  desc 'Invoke rake task on the server'
  task :invoke do
    fail 'no task provided' unless ENV['task']

    on roles(:app) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, ENV['task']
        end
      end
    end
  end

end

untuk menjalankan tugas Anda, gunakan

bundle exec cap uat deploy:invoke task=users:update_defaults

Mungkin akan bermanfaat bagi seseorang

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.