Làm cách nào để chạy nhiệm vụ cào từ Capistrano?


105

Tôi đã có một deploy.rb có thể triển khai ứng dụng của tôi trên máy chủ sản xuất của tôi.

Ứng dụng của tôi chứa một tác vụ rake tùy chỉnh (tệp .rake trong thư mục lib / task).

Tôi muốn tạo một nhiệm vụ nắp sẽ chạy tác vụ cào đó từ xa.


2
Ai đó có thể giải thích những ưu / nhược điểm của việc sử dụng #{rake}biến riêng của capistrano ? Có vẻ như nó không phải lúc nào cũng là lựa chọn tốt nhất.
lulalala

Câu trả lời:


59

Rõ ràng hơn một chút, trong của bạn \config\deploy.rb, thêm bên ngoài bất kỳ tác vụ hoặc không gian tên nào:

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

Sau đó, từ /rails_root/, bạn có thể chạy:

cap staging rake:invoke task=rebuild_table_abc

1
tốt hơn nên sử dụng / usr / bin / env rake để thiết lập rvm sẽ chọn đúng rake.
DGM

8
Với 'gói thực thi' nếu có
Bogdan Gusiev.

44

... vài năm sau ...

Hãy xem plugin rails của capistrano, bạn có thể xem tại https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14, nó có thể trông giống như sau:

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
Điều này chỉ dành cho capistrano v3.
phillbaker

Đã giúp đỡ rất nhiều. Cảm ơn! @Mirek Rusin
Nishant Shrivastava

người khác trả lời, việc sử dụng đó runsẽ hoạt động trên capistrano cho đến phiên bản 2. Từ phiên bản 3, đây là cách để đi.
Don Giulio

44

Capistrano 3 Phiên bản Chung (chạy bất kỳ nhiệm vụ cào nào)

Xây dựng một phiên bản chung cho câu trả lời của 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

Ví dụ sử dụng: cap staging "invoke[db:migrate]"

Lưu ý rằng deploy:set_rails_envyêu cầu đến từ đá quý capistrano-rails


1
Này chỉ hỗ trợ một đối số duy nhất, nếu bạn thay thế rake args[:command] với execute :rake, "#{args.command}[#{args.extras.join(",")}]" bạn có thể thực hiện một nhiệm vụ với nhiều luận cứ thích như vậy: cap production invoke["task","arg1","arg2"]
Robin Clowers

1
@ Robin Clowers Bạn có thể chuyển nhiều đối số, ví dụ cap staging invoke['task[arg1\,arg2]']. Tôi thích cách tiếp cận này hơn cách bạn đề cập vì nó phản ánh cách gọi thực tế của rake. Với phương pháp này bạn cũng có thể chuỗi nhiều nhiệm vụ, mà thường là hữu ích: cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']. Công trình cho cào 10.2.0 hoặc mới hơn
marinosb

điều này thật tuyệt - tôi muốn lưu ý, bạn cần bao gồm: ứng dụng làm một trong những vai trò máy chủ của mình.
lfender6445,

Rõ ràng điều này cần được "gọi [db: migrate]" ... Đã sửa.
Abram

@Abram với lệnh bạn đề xuất, tôi nhận được "Không biết cách xây dựng nhiệm vụ 'gọi ra"
dc10

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

Tìm thấy nó với Google - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

Đó RAILS_ENV=productionlà một gotcha - tôi đã không nghĩ về nó lúc đầu và không thể tìm ra lý do tại sao nhiệm vụ không thực hiện được gì.


2
Một cải tiến nhỏ: nếu bạn thay dấu chấm phẩy bằng && thì câu lệnh thứ hai (chạy tác vụ rake) sẽ không chạy nếu câu lệnh đầu tiên (thay đổi thư mục) không thành công.
Teflon Ted

2
Điều này sẽ không hoạt động nếu bạn đang triển khai trên nhiều máy chủ. Nó sẽ chạy tác vụ cào nhiều lần.
Mark Redding

4
người ta thực sự nên tôn trọng thiết lập cào của capistrano"cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"
kares

@Mark Redding: Bạn có thể đặt một trong các máy chủ vào vai trò riêng của nó cho các nhiệm vụ rake và hạn chế tác vụ capistrano của bạn chỉ chạy trên các máy chủ có vai trò đó không?
mj1531

Tôi đã làm điều gì đó mà tôi đã tạo một nhiệm vụ trong deploy.rb của mình. Tác vụ đó có: role =>: db trên đó để nó chỉ thực thi trên cùng một máy chủ mà tôi đã xác định là chính của mình cho db: migrate.
Mark Redding vào

20

Sử dụng lời gọi cào kiểu Capistrano

Có một cách phổ biến sẽ "chỉ hoạt động" với require 'bundler/capistrano'và các tiện ích mở rộng khác sửa đổi rake. Điều này cũng sẽ hoạt động với môi trường tiền sản xuất nếu bạn đang sử dụng nhiều tầng. Ý chính? Sử dụng các cấu hình khác nếu bạn có thể.

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
Đây là giải pháp đẹp nhất, sử dụng các giá trị capistrano nếu có
loopj

2
Có lẽ đáng nói thêm rằng nếu công việc của bạn được namespaced (tức là định nghĩa không nằm trong namespace cấp cao nhất), bạn có thể phải sử dụng top.runthay vì chỉrun
dolzenko

Cảm ơn @dolzenko. Chỉ cần tìm thấy tài liệu cho topphương pháp . Trong trường hợp chúng tôi đã xác định runtrong cùng một không gian tên, top.runlà bắt buộc, nếu không nó vẫn sẽ tìm thấy cấp cao nhất runngay cả khi nhiệm vụ được đặt trong không gian tên. Tôi đã bỏ lỡ một cái gì đó? Điều gì đã xảy ra trong trường hợp của bạn?
Captainpete

1
Tôi rõ ràng không có bất kỳ phương thức chạy nào được xác định trong cùng một không gian tên, vì vậy không chắc tại sao tôi cần điều đó. Trong mọi trường hợp Capistrano 2.0 là một lịch sử và các phiên bản tiếp theo được Rake dựa (làm cho mọi thứ dễ dự đoán hơn hy vọng)
dolzenko

16

Sử dụng capistrano-rakeđá quý

Chỉ cần cài đặt đá quý mà không cần phải làm phiền với các công thức capistrano tùy chỉnh và thực hiện các nhiệm vụ cào mong muốn trên các máy chủ từ xa như thế này:

cap production invoke:rake TASK=my:rake_task

Tiết lộ đầy đủ: Tôi đã viết nó


7

Cá nhân tôi sử dụng trong sản xuất một phương pháp trợ giúp như thế này:

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

Điều đó cho phép chạy tác vụ rake tương tự như sử dụng phương thức run (lệnh).


LƯU Ý: Nó tương tự như những gì Duke đề xuất, nhưng tôi:

  • sử dụng new_release thay vì current_release - theo kinh nghiệm của tôi, đó là điều bạn mong đợi hơn khi chạy lệnh rake;
  • tuân theo quy ước đặt tên của Rake và Capistrano (thay vì: cmd -> task and rake -> run_rake)
  • không đặt RAILS_ENV = # {rails_env} vì nơi thích hợp để đặt nó là biến default_run_options. Ví dụ: default_run_options [: env] = {'RAILS_ENV' => 'production'} # -> DRY!

5

Có một chiếc áo choàng đá quý thú vị giúp các nhiệm vụ cào của bạn có sẵn dưới dạng các nhiệm vụ Capistrano, vì vậy bạn có thể chạy chúng từ xa. capeđược ghi lại đầy đủ, nhưng đây là tổng quan ngắn về cách thiết lập tôi.

Sau khi cài đặt gem, chỉ cần thêm nó vào config/deploy.rbtệp của bạn .

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

Giờ đây, bạn có thể chạy tất cả các raketác vụ của mình cục bộ hoặc từ xa thông qua cap.

Như một phần thưởng bổ sung, capecho phép bạn đặt cách bạn muốn chạy tác vụ cào cục bộ và từ xa (không cần nữa bundle exec rake), chỉ cần thêm điều này vào config/deploy.rbtệp của bạn :

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

Lưu ý: chỉ hoạt động với Capistrano v2.x. Không tương thích với 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
Tốt. Thay đổi nó từ RAILS_ENV=productionthành RAILS_ENV=#{rails_env}cho phép nó hoạt động trên máy chủ dàn của tôi.
evanrmurphy,

2

Đây là những gì tôi đã đưa vào deploy.rb của mình để đơn giản hóa việc chạy các tác vụ rake. Đó là một trình bao bọc đơn giản xung quanh phương thức run () của 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

Sau đó, tôi chỉ chạy bất kỳ tác vụ cào nào như vậy:

rake 'app:compile:jammit'

mâu thuẫn này như định nghĩa capistrano nó biến cào riêng (được sử dụng để xác định cào để sử dụng) và do đó phá vỡ được xây dựng trong receipies ví dụ một trong đó precompiles tài sản
Michael

2

Điều này đã làm việc cho tôi:

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

Sau đó chỉ cần chạy cap production "invoke[task_name]"


1

Hầu hết đó là từ câu trả lời trên với một cải tiến nhỏ để chạy bất kỳ nhiệm vụ cào nào từ capistrano

Chạy bất kỳ nhiệm vụ cào nào từ 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

Điều này cũng hoạt động:

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

Thông tin thêm: Capistrano Run


1
{deploy_to} / current sẽ không hoạt động ở đây. Liên kết tượng trưng không thay đổi. Nếu bạn cập nhật tác vụ rake, điều này sẽ chạy mã cũ. Thay vào đó, hãy xem xét sử dụng {release_path}.
Mark Redding

thông tin nhiều hơn là thư rác?
hcarreras

1

Nếu bạn muốn có thể chuyển nhiều đối số, hãy thử điều này (dựa trên câu trả lời của 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

Sau đó, bạn có thể chạy một tác vụ như sau: cap production invoke["task","arg1","arg2"]


0

Vì vậy, tôi đã làm việc trên này. nó nối để hoạt động tốt. Tuy nhiên, bạn cần một trình định dạng để thực sự tận dụng mã.

Nếu bạn không muốn sử dụng trình định dạng, chỉ cần đặt mức nhật ký thành chế độ gỡ lỗi. Các semas này để h

SSHKit.config.output_verbosity = Logger::DEBUG

Cap Stuff

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

Đây là trình định dạng tôi đã xây dựng để làm việc với đoạn mã trên. Nó dựa trên: textimple được tích hợp trong sshkit nhưng không phải là một cách tồi để gọi các tác vụ tùy chỉnh. Ồ, nhiều cái này không hoạt động với phiên bản mới nhất của sshkit gem. Tôi biết nó hoạt động với 1.7.1. Tôi nói điều này bởi vì nhánh chính đã thay đổi các phương thức SSHKit :: Command có sẵn.

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

Các câu trả lời trước đó không giúp được tôi và tôi đã tìm thấy câu trả lời này: Từ 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

để chạy nhiệm vụ của bạn sử dụng

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

Có thể nó sẽ hữu ích cho ai đó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.