How to run bin/webpack with capistrano and rails - ruby-on-rails

So I have a rails 6 app that doesn't load any css or javascript assets when I run cap production deploy.
So what I do is after I run cap production deploy, I ssh into my server, navigate to myapp/current/ and run bin/webpack and then everything works. So I'd like my deployment process to do this for me so that I don't have to go into my server and run this everytime.
I've looked on how to run custom capistrano "tasks," but all the tutorials show you only how to run custom rake tasks, but this isn't a rake task.
I don't run rake bin/webpack, i just run bin/webpack.
So how I would go about implementing this in my capistrano setup? I assume I have to enter some sort of capistrano command in my deploy.rb.
Any ideas?

Capistrano at its core is just ssh. It's doing something similar to what you're doing when you ssh (although slightly different because it's not typically an interactive session).
You could write a custom task to run Webpack.
To do that you need to load them first if they're not already being loaded.
Check for this line in your Capfile or add it yourself. This will load your custom tasks which come in the form of rake tasks:
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
Then, create a task in that folder. Call it something like lib/capistrano/tasks/webpack.rake
namespace :webpack do
task :build do
on roles(:app) do
within release_path do
# https://github.com/capistrano/sshkit#the-command-map
with path: "#{release_path}/bin:$PATH" do
execute :webpack
end
end
end
end
end
Now, you need to tell Capistrano when to execute it. I usually do this with before/after hooks. For more info check out Capistrano flow
after the namespace block add:
# lib/capistrano/tasks/webpack.rake
# ...
after "deploy:updated", "webpack:build"
you can test out task execution with bundle exec cap production deploy --dry-run

Related

Cron job not being updated by whenever gem

Having a series of rake tasks that should be translated by the whenever gem into the cron file, I was wondering why the takes shows were pointing to an old release.
It cannot be asserted that whenever is active somehow, even though it is listed in the gem file (and associated lock file) and deployment refers to whenever in the deployment as follows:
tar: DEBUG [1f7d4e56] bin/whenever: time stamp 2016-01-08 15:01:20 is 88.787104175 s in the future
update Checking bundle exec whenever -v returns the proper version. Need bundle exec there...
Capfile includes require "whenever/capistrano" after calls to bundler and rails.
require 'capistrano/bundler'
require 'capistrano/rails'
require 'whenever/capistrano'
Note: this is being tested in development mode.
Functional answer. The instructions are misleading If you don't need different jobs running on different servers in your capistrano deployment, then you can safely stop reading now and everything should just work the same way it always has. Keep on reading.
The nugget is nested after this statement. Roles default to [:db]. Thus two sources of error are possible:
different job_roles on different machines are not specified in schedule.rb
Check your environment file. If "db" is not listed, whenever will not fire.
I had the same issues with using Capistrano whenever plugin, I solved it by making custom deploy shell scripts, cap production deploy being one command of many, and then inclding cap production cron:regen; inside this script I called deploy.sh, with the command inside the deploy.rb being:
namespace :cron do
desc "restart cron"
task :regen do
on roles(:app) do |host|
rails_env = fetch(:stage)
execute_interactively "crontab -r;bundle exec whenever --update-crontab;crontab -l;"
end
end
end
def execute_interactively(command)
port = fetch(:port) || 22
exec "ssh root##{fetch(:ip)} -t 'cd SERVER_PATH_OF_YOUR_APP && #{command}'"
end
I use these functions for all types of different commands, since Capistrano still gives me problems with a lot of native plugins it uses.
If you're not happy with the whenever/capistrano, you can create yourself a simple Capistrano task to update the cron jobs:
namespace :deploy do
desc "Update crontab with whenever"
task :update_cron do
on roles(:app) do
within current_path do
execute :bundle, :exec, "whenever --update-crontab #{fetch(:application)}"
end
end
end
after :finishing, 'deploy:update_cron'
end
The task will be called when the code deployment is finished.

Rails - Run Rake tasks with Capistrano

Im scratching my head here wondering if I'm barking up the wrong tree. I have a server which I've deployed a Rails app onto using Capistrano. Recently I added a new data type to one of the models, and now I need to run a Rake task to update the existing records.
After a lot of Googling I'm starting to wonder if people use Rake tasks with Capistrano. Some forum posts from 2013 or so mention that Capistrano supports the .rake extension. Whereas other posts I've found indicate that Capistrano has its own task automation system, and is incompatible with rake.
I found Cape, but I'm unsure if this is what I'm looking for as it seems to convert Rake tasks into cap recipes. Its possible I'm mistaken on this point, I really don't have any experience working with Capistrano or even working in the full stack spectrum.
What I'm wondering is this: How do I run a simple Rake task on my remote server?
Some quick points for clarity, I've installed the app on the latest Ubuntu LTS, 14.10 if memory serves. I followed the tutorial found here. I have full sudo access and I can ssh into the server.
thanks in advance for helping a noob
If you need to update models, you can of course write a Rails migration - this will ensure that it's run if it hasn't been run yet.
The easiest way to execute a rake task on the server would be just via ssh if it's a one-time task. See the last paragraph in the tutorial you mentioned:
cd /opt/www/testapp/current ; bin/rake RAILS_ENV=production db:seed
To answer your original question about rake: you can execute rake tasks via capistrano similar to how you would execute it locally, only within the capistrano script. Here's an example:
deploy.rb:
namespace :rake do
desc "My task"
task :my_task do
on roles(:app) do
within "#{current_path}" do
with rails_env: :production do
execute :rake, "my_task"
# !!!see NOTE at end of answer!!!
end
end
end
end
end
You can view all your cap tasks via cap -T locally. The capistrano task I wrote above should show up as cap tasks:my_rake_task.
If you want to be ably to run any available rake task without configuring, do the following:
namespace :rake do
desc "Invoke rake task"
task :invoke do
on roles(:app) do
within "#{current_path}" do
with rails_env: :production do
execute :rake, ENV['task']
# !!!see NOTE at end of answer!!!
end
end
end
end
end
Then you can write:
cap production deploy:invoke task=my:rake:task
NOTE: you might want to replace the execution line with
run "bin/rake RAILS_ENV=#{rails_env} #{ENV['task']}"
to use the same syntax as the tutorial (without the binstubs you might need to configure capistrano/bundler and capistrano/rbenv first ...)
Check out capistrano-rake
Once installed, run any rake task on your production/staging servers without messy capistrano recipes by simply doing this:
$ cap production invoke:rake TASK=your:rake:task
Full Disclosure: I wrote it

How to run only rake task once

I am using Ruby on Rails and Heroku.
I would like something like rake db:migrate, where it will only run the parts that have not been run before.
I can set a rake task that can run other rake task, but is there in way to only run those that did not run before?
What are any alternative, if I want rake tasks to be run automatically?
first of, running a rake task twice, ie rake db:migrate will neither duplicate nor overwrite your database columns if they already exist.
For example capistrano, used to deploy your rails app to basically anywhere, will rerun tasks like db:migrateor assets:precompile every time you deploy your app. So no need to worry about that really.
To run tasks automatically you will need something like a cron job. Whenever is a great ruby gem that allows you to install a job like this with the beloved ruby syntax.
After installing the gem and running wheneverize . in the root of your rails app, you may edit the scheduler.rb and add something like:
every :sunday, :at => '12pm' do
rake my:awesome:task
end
The Github page as well as the default scheduler.rb hold many useful examples of how these jobs are built.
with whenever --update-crontab you can write your rubyesque cronjobs into the crontab, which will run your tasks periodically at the time you want them to.
** edit
multiple tasks in one:
task :setup => [:a, :b, :c]
task :a do
%x(bash command)
end
task :b do
rake db:migrate
end
task :c do
rake whatever
end

Ruby on Rails, Capistrano, Whenever: Cron jobs not getting executed at production server

Ruby on rails + Capistrano + Whenever gem
I executed whenever --update-crontab but still cron job is not getting executed at production server. There are no logs in the log file. Though everything works well at development where capistrano is not required.
schedule.rb
set :output, "../dev/log/cron.log"
every 1.minute do
runner "SOME_TASK"
end
deploy.rb
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
capfile
require "whenever/capistrano"
What's the issue? How to debug?
I've had similar issues when deploying our apps.
If you check the log files of crontab you'll see that it does execute but its being executed in the wrong context.
For example:
You think this code should execute but it doesn't:
every 1.minute do
runner "bundle exec rake db:seed"
end
Instead you should supply the absolute path tot the executable. Cron doesn't know in what kind of context it should be run, it just executes.
We use rbenv in our deployment and we use shims of gems. So I just supplied cron with the absolute path to the executable.
This code does run:
every 1.minute do
runner "/usr/bin/shims/bundle exec rake db:seed"
end

Loading initializers during assets precompile

I am trying to precompile the assets while deploying to production environment. I am also trying to automate it for first time installation on a server using capistrano. It looks like none of the initializer's are getting loaded during the assets precompile process.
I am facing these two problems
For the first time installation I am generating a initializer file(initializers/freshinstall.rb) on the fly with the below content
config.assets.initialize_on_precompile = false
so that precompile doesn't check the database which doesn't exist yet
I also have some vendor files, and their locations are set in the asset pipeline, and are placed in separate initializer file initializers/vendor.rb
MyApp::Application.config.assets.paths << "#Rails.root}/vendor/assets/images/xxxx" << "# {Rails.root}/vendor/assets/images/xxxx/helpers"
MyApp::Application.config.assets.paths << "#{Rails.root}/vendor/assets/stylesheets/xxxx"
MyApp::Application.config.assets.paths << "#{Rails.root}/vendor/assets/stylesheets/yyyy" << "#{Rails.root}/vendor/assets/images/yyyy"
When capistrano runs the assets precompile task, its not able to find the vendor paths or stopping it from looking into the database. This brings me to a conclusion that the initializer's are not getting loaded. After going through some stackoverflow questions. I even added a railtie to config/application.rb
module AssetsInitializers
class Railtie < Rails::Railtie
initializer "assets_initializers.initialize_rails",
:group => :assets do |app|
require "#{Rails.root}/config/initializers/freshinstall.rb"
require "#{Rails.root}/config/initializers/vendor.rb"
end
end
end
But I still don't see any initializers getting loaded. Can I get some info on the internals of the boot process of an rail application, and also why the initializers are not getting loaded during the assets precompile process.
Some documentations would be really helpful to understand this. The Rails documentation is very minimal with respect to railtie and the initializer method.
http://guides.rubyonrails.org/configuring.html
Thank you in advance
Finally was able to figure out how to do it. This works for my single server capistrano deployment. Below is the capistrano task for my new_deploy on to a fresh server.
set :fresh_install, false
task :new_deploy do
set :fresh_install,true
deploy.setup
#The assets:precompile process is part of the deploy.update. Before the precompile process, we will create database.
deploy.update
deploy.migrate
run_seed
#load unicorn server
end
Dont do any configuration setting mentioned below
config.assets.initialize_on_precompile = false # no need of this in application.rb
Instead just before assets:precompile create your database
before "deploy:assets:precompile" , "yourapp:create_database"
See that you check if the fresh install flag is set, then only create the database.This method will also be called during regular deploy when ever you are updating the server with latest revision. During that scenario fresh_install flag will be false.
desc 'Create a new database'
task :create_database, :roles => :app do
if fresh_install
run "cd #{release_path}; bundle exec rake db:create RAILS_ENV=#{rails_env}"
end
end

Resources