ExecJS::RuntimeUnavailable

Hi there,

I deployed to a rails app to fly successfully but when I try to run rails db:migrate I get the following error: ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.

I understand that it might be because of Node (the app has bootstrap)? But the dockerfile installs node and its dependent packages? Also, not sure why this comes up at the db migrate stage?

Any ideas on how to fix this?

Hi Nandu,

can you share your dockefile & fly.toml, I’m thinking this issue could either be from a missing release command in the fly.toml or a missing Node package that docker missed installing.

I’d also like to see your Gemfile.

If this Dockerfile was produced by us, and the Gemfile contains execjs, the Dockerfile should install node in the base image so that it is available during deployment, and the dockerfile should look something like the following expected test results. If it doesn’t, there is a bug somewhere and I’d like to fix it.

If the Dockerfile was not produced by us, try generating a new one using:

bin/rails generate dockerfile

Dockerfile:

# syntax = docker/dockerfile:1

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
ARG RUBY_VERSION=2.6.7
FROM ruby:$RUBY_VERSION-slim as base

LABEL fly_launch_runtime="rails"

# Rails app lives here
WORKDIR /rails

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_WITHOUT="development:test" \
    BUNDLE_DEPLOYMENT="1"

# Update gems and bundler
RUN gem update --system --no-document && \
    gem install -N bundler

# Install packages needed to install nodejs
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install Node.js
ARG NODE_VERSION=14.16.1
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    rm -rf /tmp/node-build-master


# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential git libpq-dev node-gyp pkg-config python

# Install yarn
ARG YARN_VERSION=1.22.11
RUN npm install -g yarn@$YARN_VERSION

# Build options
ENV PATH="/usr/local/node/bin:$PATH"

# Install application gems
COPY --link Gemfile Gemfile.lock ./
RUN bundle install && \
    bundle exec bootsnap precompile --gemfile && \
    rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git

# Install node modules
COPY --link package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Copy application code
COPY --link . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets:precompile


# Final stage for app image
FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Run and own the application files as a non-root user for security
RUN useradd rails --home /rails --shell /bin/bash
USER rails:rails

# Copy built artifacts: gems, application
COPY --from=build /usr/local/bundle /usr/local/bundle
COPY --from=build --chown=rails:rails /rails /rails

# Deployment options
ENV RAILS_LOG_TO_STDOUT="1" \
    RAILS_SERVE_STATIC_FILES="true"

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/rails", "server"]

Gemfile:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.7'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
gem 'rails', '~> 6.0.6', '>= 6.0.6.1'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# Use SCSS for stylesheets
gem 'sass-rails', '>= 6'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

gem 'devise'

#gems added by me
gem 'net-http'
gem 'uri', '0.10.0'
gem 'wicked'

gem 'autoprefixer-rails', '10.2.5'
gem 'font-awesome-sass', '~> 5.6.1'
gem 'simple_form', github: 'heartcombo/simple_form'
group :development, :test do  gem 'pry-byebug'
  gem 'pry-rails'
  gem 'dotenv-rails'
  gem 'rspec-rails'

  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem "dockerfile-rails", ">= 1.2", :group => :development

fly.toml:

# fly.toml file generated for app-name on 2023-05-17T12:33:16+02:00

app = "app-name"
kill_signal = "SIGINT"
kill_timeout = 5
primary_region = "iad"
processes = []

[env]

[experimental]
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 3000
  min_machines_running = 0
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "30s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

[[statics]]
  guest_path = "/rails/public"
  url_prefix = "/"

I’m traveling today so I may not be able to look at this fully until tomorrow. Looks like the Dockerfile was generated by us, looks like it installs Node in the base image and adds node to the path, so it should work.

You are right that bootstrap requires execjs, but I don’t see bootstrap in your Gemfile. But I must be missing something because otherwise the dockerfile generator wouldn’t have installed Node in the base image instead of the “throwaway” build image.

You are using an old and unsupported version of Ruby, but that shouldn’t be an issue; however it is slowing me down as I can’t install that Gemfile with a current version of Ruby, and so far I’ve failed to install 2.6.7 with either asdf or rvm. Incidentally, you also appear to be using Nomad (and older version of fly’s runtime), but again, that shouldn’t affect this issue.

The one question I can answer is why this is happening at migration time. Rails loads and initializes your entire app in order to run migrations - even parts that aren’t used to perform the migration. Bootstrap isn’t used during the migration, but does check for nodejs when initializing.

Has anything changed since last week? It worked fine when I ran db:migrate around this time last week.

How are you running db:migrate?

With Rails 6, you should be running db:prepare, and bin/docker-entrypoint should be doing that for you automatically. Since you are using postgres, you can move that to a release step (see Dockerfiles and fly.toml · Fly Docs for how), but that just changes when the step runs.

Like this:

fly ssh console
cd /rails
bin/rails db:migrate
bin/rails db:seed

Commands to try within fly ssh console:

/usr/local/node/bin/node -v

This should return v14.16.1

echo $PATH

/usr/local/node/bin should be included in the string that is returned.

which node

Should return /usr/local/node/bin/node

Within fly ssh console,

echo $PATH returns the following:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

which node:

-bash: /usr/bin/which: Input/output error

I tried using /usr/bin/which node and I got -bash: /nandurajagopala/bin/which: No such file or directory (usr being my name btw)

and:

/user/local/node/bin/node -v gives -bash: /usr/local/node/bin/node: No such file or directory

Very puzzling. The Dockerfile you posted would create a machine that installs node and adjusts the PATH. The machine you are shelling into does neither.

If your only issue is that you can’t run db:migrate, you can always install a version of node that won’t actually be used during the migration:

fly ssh console
cd /rails
apt-get update
apt-get install -y nodejs
bin/rails db:migrate
bin/rails db:seed

This is what I get:

image

Also this root thing didn’t come up last week. It’s new. Is that normal?

It is the new normal. If you type sh you will get the old shell.

As to Input/output error… yet another puzzle.

any updates on this?

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.