Why does Capistrano deployment fail at assets:precompile without error? - ruby-on-rails

I've tried everything I could think of, but I can't get deployment to work.
The app needs to deploy to a VPS hosted by Alwaysdata and running ruby 2.6.2, using Capistrano for deployment.
It's a Rails 6.0.2.2 application, using webpack for JS and sprockets for legacy scripts, all images and CSS.
# On local machine (MacOS)
$ bundle exec cap production deploy
00:00 git:wrapper
00:01 git:check
00:03 deploy:check:directories
00:03 deploy:check:linked_dirs
00:03 deploy:check:make_linked_dirs
00:05 git:clone
00:06 git:update
00:08 git:create_release
00:10 deploy:set_current_revision
00:10 deploy:symlink:linked_files
00:12 deploy:symlink:linked_dirs
00:18 deploy:config:bundler
00:20 bundler:install
00:20 deploy:assets:precompile
#<Thread:0x00007fb35ba959f0#/Users/Goulven/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/sshkit-1.21.0/lib/sshkit/runners/parallel.rb:10 run> terminated with exception (report_on_exception is true):
Traceback (most recent call last):
/Users/Goulven/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/sshkit-1.21.0/lib/sshkit/command.rb:97:in `exit_status=': rake exit status: 1 (SSHKit::Command::Failed)
rake stdout: Nothing written
rake stderr: Nothing written
INFO [3def24f1] Running bundle exec rake assets:precompile as vtcontrol#ssh-vtcontrol.alwaysdata.net
DEBUG [3def24f1] Command: cd /home/www/app/releases/20200409174918 && ( export NODE_ENVIRONMENT="production" RAILS_ENV="production" RAILS_GROUPS="" ; bundle exec rake assets:precompile )
Running the last command locally or on the server does not produce any errors, only warnings:
# On production server:
$ cd /home/www/app/releases/20200409174918 && ( export NODE_ENVIRONMENT="production" RAILS_ENV="production" RAILS_GROUPS="" ; bundle exec rake assets:precompile )
yarn install v1.22.4
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents#1.2.12: The platform "linux" is incompatible with this module.
info "fsevents#1.2.12" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
warning " > webpack-dev-server#3.10.3" has unmet peer dependency "webpack#^4.0.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware#3.7.2" has unmet peer dependency "webpack#^4.0.0".
success Already up-to-date.
Done in 0.62s.
Hypothesis I've thought of:
Running out of RAM. Happens mainly with Digital Ocean, provider excludes that possibility, and anyway it would not compile when sshing to the server.
An issue with node vs nodejs. This used to nag me but it no longer happens, at first because I used sprockets only and added the mini_racer gem, which packages node for ExecJS, then because I included Bootstrap using webpacker instead of Sprockets, thus removing the dependency on autoprefixer-rails which errors out when an old version of nodejs is present alongside node.
Capistrano incorrectly interpreting yarn/webpacker warnings for failures. I extracted Bootstrap into its own app/javascripts/bootstrap.js because webpacker complained that the generated JS was too large, so this can be ruled out. Yarn complains about unmet peer dependencies but these are dev dependencies, I don't think it should matter. This might be the problem, but how can I test that?
Anything else I should try? Could using webpack and sprockets cause conflicts in production for instance? It works fine in development, and the generated assets should not overwrite one another.
Here are the relevant portions of my Gemfile:
# Gemfile
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
group :production do
# Used to load env vars from an .env file during deploy
gem 'dotenv-rails'
end
group :development do
gem 'capistrano', '~> 3.13.0', require: false
gem 'capistrano-rails', '~> 1.4', require: false
gem 'capistrano-bundler', '~> 1.6', require: false
gem 'capistrano-rails-console', require: false
end
And finally the relevant portion of my Capfile and deploy.rb:
# Capfile
require 'capistrano/bundler'
require 'capistrano/rails'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/rails/console'
require 'dotenv'
Dotenv.load
# config/deploy.rb
# Setup bundler
# Unset capistrano/bundler default flags because Bundler has deprecated them
set :bundle_flags, '--quiet'
set :bundle_path, nil
set :bundle_without, nil
before 'bundler:install', 'deploy:config:bundler'
# Remove gems no longer used to reduce disk space used
# This command requires loading capistrano/bundler in Capfile
after 'deploy:published', 'bundler:clean'
# Skip migration if files in db/migrate were not modified
# This command requires loading capistrano/rails in Capfile
set :conditionally_migrate, true
# Rails app server manages the database
set :migration_role, :app
# Defaults to nil (no asset cleanup is performed)
# If you use Rails 4+ and you'd like to clean up old assets after each deploy,
# set this to the number of versions to keep
set :keep_assets, 2
Thanks for your help!

Okay, after days of trying everything I could think of I tried something I'd already tested but with the correct syntax this time, I guess, because it works now.
Here is what I needed to add to Capistrano's config file to ensure Yarn was available when deploying:
# In deploy.rb
# Add or adjust default_env to append .npm-packages to $PATH:
set :default_env, {
PATH: '$HOME/.npm-packages/bin/:$PATH',
NODE_ENVIRONMENT: 'production'
}
Explanation: VPS users are allowed to install binaries like Yarn "globally" (using npm install --global yarn). Under-the-hood the binary is installed in $HOME/.npm-packages/bin, and this folder is added to the $PATH for interactive/login shell sessions. Since Capistrano does its utmost to NOT pick up this, we have to force-feed the updated $PATH in deploy.rb.

Thanks for pointing me in the right direction. I had the same error and it turned out to be a memory issue. For anyone with the same issues, check if you ran out of memory with free -m during compilation. If you ran out you'll see something like -bash: fork: Cannot allocate memory.
I'm using Digitalocean and my solution was to add swap space: https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-18-04

Related

Rails capistrano /usr/bin/env no file or such directory

I have a RoR application and when i try to deploy to my server via capistrano, i got this error message
/.rvm/gems/ruby-2.6.4#railsapp1/gems/sshkit-1.21.2/lib/sshkit/command.rb:97:in `exit_status=': bundle exit status: 127 (SSHKit::Command::Failed)
bundle stdout: Nothing written
bundle stderr: /usr/bin/env: bundle: No such file or directory
this is happen when capistrano run task bundler:config (below)
00:52 bundler:config
01 bundle config --local deployment true
01 /usr/bin/env: bundle
01 : No such file or directory
can anyone help me with this ? My server is using ruby virtual env instead of rvm and rbnev
Edit:
I already install bundler, but to run it i have to..let's say activate the ruby first with this script
/home/myusername/rubyvenv/staging_rails__app1/2.6/bin/activate
And i already add that script into capistrano as the first task executed, but the error is still there, is there something that i miss ?
namespace :deploy do
before 'git:wrapper', :run_on_server
end
task :run_on_server do
on roles(:app) do
execute 'source /home/myusername/rubyvenv/staging_rails__app1/2.6/bin/activate'
end
end
It seems you don't have the bundler gem installed in your server environment (which would provide the bundle executable).
You can install bundler with gem install bundler or gem install bundler -v VERSION (with VERSION being the exact version of bundler you are using to develop the app which is indicated in the last line of your Gemfile.lock.

"bundle exec rake" doesn't honor "without"

On a GitLab installation from source, I'm having problems running binaries such as rake. I've never seen similar problems with my own Ruby or Rails projects:
# bundle config
Set for your local app (/mnt/data/www/gitlab.bitcetera.com/source/gitlab/.bundle/config): "1"
path
Set for your local app (/mnt/data/www/gitlab.bitcetera.com/source/gitlab/.bundle/config): "vendor/bundle"
without
Set for your local app (/mnt/data/www/gitlab.bitcetera.com/source/gitlab/.bundle/config): "development:test:unicorn:mysql:kerberos:metrics"
disable_shared_gems
Set for your local app (/mnt/data/www/gitlab.bitcetera.com/source/gitlab/.bundle/config): "true"
# bundle install --deployment --without development test unicorn mysql kerberos metrics
# bundle config
The Gemfile's dependencies are satisfied
# bundle exec rake --tasks
rake aborted!
LoadError: cannot load such file -- haml_lint/rake_task
Looking at the relevant section of the Gemfile:
group :development, :test do
[...]
gem 'haml_lint', '~> 0.21.0', require: false
[...]
end
Of course the haml_lint gem is missing, after all, it's in the "development" and "test" groups only which I've excluded by "without".
Any idea what's going on here?
Figured it out, kinda daft reason: RAILS_ENV should have been set automatically yet it wasn't so of course things go awry.

Capistrano throws /usr/bin/env: ruby: No such file or directory when performing a deploy:migration

I set up Capistrano to make the deploy of my app. I made it in steps, so first I set up the code deployment, so I commented all the roles but :app.
I'm using rvm and I had some problems with it. The biggest problem was an error that said /usr/bin/env: ruby: No such file or directory. I solved them using the gem capistrano/rvm and requiring it in the Capfile and adding the following line to the deploy.rb file:
set :default_env, { path: "/usr/local/rvm/gems/ruby-2.0.0-p247#global/bin:$PATH" }
Once the code deploying runned correctly I activated de :db role in order to perform migrations. I get the same error but I can't find the solution this time.
~$ cap production deploy:migrate
…
…
INFO [85d6241d] Running bundle exec rake db:migrate on 10.10.51.10
DEBUG [85d6241d] Command: cd [PROJECT_SRC]/current
&& ( PATH=/usr/local/rvm/gems/ruby-2.0.0-p247#global/bin:$PATH RAILS_ENV=production bundle exec rake db:migrate )
DEBUG [85d6241d] /usr/bin/env: ruby: No such file or directory
cap aborted!
This command runs correctly when I execute it directly in the shell.
Thank you in advance!
Finally it worked using gem 'rvm1-capistrano3', require: false. It seems the best option for my setup (Rails4.0.1, ruby-2.0.0-p247, capistrano3). It didn't require special configuration.
You can find it here.
Hope it helps someone!
I had similar problem and this gem helped me:
https://github.com/wayneeseguin/rvm-capistrano
If you are not using rvm, then the issue is usually you'll have to manually install bundler gem on the server.
gem install bundler
Have you tried offical capistrano gems? That helped me, maybe your use case is similiar.
Gemfile:
...
gem 'capistrano', '~> 3.2.0'
gem 'capistrano-rvm'
gem 'capistrano-rails'
...
Capfile:
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/migrations'
...

capistrano script fails because a test-group gem is not found

I'm deploying to a staging server which is running in environment=development. My deploy script fails with the message Could not find gem 'webmock (>= 0) ruby' in the gems available on this machine. but I cannot see why the script should ever need that gem because my Gemfile only lists it in the test group.
Do you have any idea why my staging server is trying to require webmock during deployment?
My deploy script
Here is the command from my deploy script fails:
executing ["cd /var/www/clu2/staging/releases/20130429170940 && bundle exec whenever --update-crontab staging --set environment=development --roles db"]
One command earlier, the script runs bundle install, omitting the test gems:
executing ["cd /var/www/clu2/staging/current && bundle install --without=test --no-update-sources"]
My usage of webmock is only in test
You can see that webmock is only required in my spec_helper file:
$ grep -r webmock .
./Gemfile: gem "webmock"
./Gemfile.lock: webmock (1.11.0)
./Gemfile.lock: webmock
./spec/spec_helper.rb: require "webmock/rspec"
You can see that webmock is specified as a test gem in my Gemfile:
group :test do
gem 'spork-rails' # pre-load rails environment for faster test launches
gem "webmock"
end
You should explicitly set :bundle_without config option in your staging deployment configuration file (do you use it? If not take a look at capistrano-ext gem which provides multistage features):
set :bundle_without, []
That's because :bundle_without is defined like this in production deployment:
set :bundle_without, [ :development, :test ]
One more thing.
I think that you should run your stage machine with production env. Staging machine is commonly used to emulate how code is working in production.

bundle install in Capistrano not installing assets gems in Rails

When I run cap deploy, the gems in the :assets group are not installed.
This is a problem because I'm using precompiled assets, and Capistrano has to run rake assets:precompile on the server. That will fail unless the assets gems are installed.
I can work around this problem by manually running bundle install within the correct release directory. But obviously this isn't the proper workflow.
Here's the full command Capistrano is executing to install the gems on each deploy:
rvm_path=/usr/local/rvm /usr/local/rvm/bin/rvm-shell 'default' -c 'cd
/home/deploy/rails_apps/vlc/releases/20120223192328 && bundle install --gemfile
/home/deploy/rails_apps/vlc/releases/20120223192328/Gemfile --path
/home/deploy/rails_apps/vlc/shared/bundle --deployment --quiet --without development test'
Here's the end, which I think might be part of the problem:
--deployment --quiet --without development test'
Evidently, these flags cause Bundler to install without the :assets group. What is the expected behavior here? Is what I'm seeing out of the ordinary? (I'm guessing so, since it doesn't make sense for Capistrano to deliberately refrain from installing a gem group that it's about to use.)
As a side note, I also note this line in application.rb:
Bundler.require(*Rails.groups(:assets => %w(development test)))
I'm assuming nothing in application.rb would affect a bundle install, since Rails doesn't boot for that. But please correct me if this line is actually relevant to my problem.
--without is remembered option, check in your project dir / on server the file .bundle/config it's possible it already contains something like this:
---
BUNDLE_WITHOUT: assets

Resources