Can't (re)deploy Rails 7: LoadError: cannot load such file -- /rails/lib/tasks/fly.rake

I’ve tried for days to deploy a new version of an already running production application (Rails 7) an it doesn’t work. The app was set up about 8 months ago and has been automatically migrated to the fly.io V2 platform a few days ago. This is the output I get every single time and yes, the fly.rake file exists and can be executed locally without any issues:

Running my-secret-app-name release_command: bin/rails fly:release
  Waiting for 5683d52ea1078e to get exit event
Error release_command failed running on machine 5683d52ea1078e with exit code 1.
Check its logs: here's the last 100 lines below, or run 'fly logs -i 5683d52ea1078e':
  Pulling container image registry.fly.io/my-secret-app-name:deployment-01H77P4S2GJMXWQQMF4HM9DABF
  Successfully prepared image registry.fly.io/my-secret-app-name:deployment-01H77P4S2GJMXWQQMF4HM9DABF (5.804098525s)
  Configuring firecracker
  [    0.050155] PCI: Fatal: No config space access function found
   INFO Starting init (commit: b437b5b)...
   INFO Preparing to run: `/rails/bin/docker-entrypoint bin/rails fly:release` as rails
   INFO [fly api proxy] listening at /.fly/api
  2023/08/07 09:45:50 listening on [fdaa:1:3a4:a7b:1c2:f8b:6a3b:2]:22 (DNS: [fdaa::3]:53)
  rails aborted!
  LoadError: cannot load such file -- /rails/lib/tasks/fly.rake
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/engine.rb:661:in `load'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/engine.rb:661:in `block in run_tasks_blocks'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/engine.rb:661:in `each'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/engine.rb:661:in `run_tasks_blocks'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/application.rb:501:in `run_tasks_blocks'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/engine.rb:464:in `load_tasks'
  /rails/Rakefile:10:in `<main>'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/commands/rake/rake_command.rb:20:in `block in perform'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/commands/rake/rake_command.rb:18:in `perform'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/command.rb:51:in `invoke'
  /rails/vendor/bundle/ruby/3.2.0/gems/railties-7.0.6/lib/rails/commands.rb:18:in `<main>'
  <internal:/usr/local/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
  <internal:/usr/local/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
  /rails/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
  /rails/bin/rails:4:in `<main>'
  (See full trace by running task with --trace)
   INFO Main child exited normally with code: 1
   INFO Starting clean up.
   WARN hallpass exited, pid: 257, status: signal: 15 (SIGTERM)
  2023/08/07 09:45:51 listening on [fdaa:1:3a4:a7b:1c2:f8b:6a3b:2]:22 (DNS: [fdaa::3]:53)
  [    2.300466] reboot: Restarting system
  machine restart policy set to 'no', not restarting
Error: release command failed - aborting deployment. error release_command machine 5683d52ea1078e exited with non-zero status of 1

(“my-secret-app-name” is not the real name of the app!)

This is what I did:

fly config save
rails generate dockerfile --compose

fly.toml:

# fly.toml app configuration file generated for my-secret-app-name on 2023-08-04T11:57:45+02:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = "my-secret-app-name"
primary_region = "fra"
kill_signal = "SIGINT"
kill_timeout = "5s"

[experimental]
  auto_rollback = true

[build]
  [build.args]
    BUILD_COMMAND = "bin/rails fly:build"
    SERVER_COMMAND = "bin/rails fly:server"

[deploy]
  release_command = "bin/rails fly:release"

[env]
  PORT = "8080"

[[mounts]]
  source = "riedl_konfigurator_data"
  destination = "/data"
  processes = ["app"]

[[services]]
  protocol = "tcp"
  internal_port = 8080
  processes = ["app"]

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

  [[services.ports]]
    port = 443
    handlers = ["tls", "http"]
  [services.concurrency]
    type = "connections"
    hard_limit = 25
    soft_limit = 20

  [[services.tcp_checks]]
    interval = "15s"
    timeout = "2s"
    grace_period = "1s"

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

fly.rake:

# frozen_string_literal: true

# commands used to deploy a Rails application
namespace :fly do
  # BUILD step:
  #  - changes to the filesystem made here DO get deployed
  #  - NO access to secrets, volumes, databases
  #  - Failures here prevent deployment
  task :build => "assets:precompile"

  # RELEASE step:
  #  - changes to the filesystem made here are DISCARDED
  #  - full access to secrets, databases
  #  - failures here prevent deployment
  task :release => "db:migrate"

  # SERVER step:
  #  - changes to the filesystem made here are deployed
  #  - full access to secrets, databases
  #  - failures here result in VM being stated, shutdown, and rolled back
  #    to last successful deploy (if any).
  task :server => :swapfile do
    sh "bin/rails server"
  end

  # optional SWAPFILE task:
  #  - adjust fallocate size as needed
  #  - performance critical applications should scale memory to the
  #    point where swap is rarely used.  'fly scale help' for details.
  #  - disable by removing dependency on the :server task, thus:
  #        task :server do
  task :swapfile do
    sh "fallocate -l 512M /swapfile"
    sh "chmod 0600 /swapfile"
    sh "mkswap /swapfile"
    sh "echo 10 > /proc/sys/vm/swappiness"
    sh "swapon /swapfile"
  end
end

Dockerfile (No changes):

# syntax = docker/dockerfile:1

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

# 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


# 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 curl libpq-dev libvips node-gyp pkg-config python-is-python3

# Install JavaScript dependencies
ARG NODE_VERSION=16.16.0
ARG YARN_VERSION=3.6.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 && \
    corepack enable && \
    corepack prepare yarn@$YARN_VERSION --activate && \
    rm -rf /tmp/node-build-master

# 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 curl imagemagick libvips postgresql-client && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

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

# Run and own only the runtime files as a non-root user for security
ARG UID=1000 \
    GID=1000
RUN groupadd -f -g $GID rails && \
    useradd -u $UID -g $GID rails --create-home --shell /bin/bash && \
    chown -R rails:rails db log storage tmp
USER 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"]

I also tried to add this to production.rb:

config.eager_load = true # Was already there
config.rake_eager_load = true

And this to the application.rb:

config.eager_load_paths << Rails.root.join("lib")
config.eager_load_paths << Rails.root.join("lib/tasks")

config.enable_dependency_loading = true
config.autoload_paths << Rails.root.join("lib")
config.autoload_paths << Rails.root.join("lib/tasks")

Nothing works and its driving me crazy!

Looks like that was just before the Cut over to Rails Dockerfile Generator on Sunday 29 Jan 2023.

The new dockerfiles don’t use lib/tasks/fly.rake so you can delete it. With apps v2, fly.toml has changed quite a bit, so replace yours with the following:

app = "my-secret-app-name"
primary_region = "fra"
console_command = "/rails/bin/rails console"

[build]

[deploy]
  release_command = "./bin/rails db:prepare"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
  processes = ["app"]

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

Take a look at auto_stop_machines and auto_start_machines. If you want your machine to run 24/7, change both of these to false. If you leave these values as they are, your machine(s) will be stopped when idle.

You were also running with a swapfile. That, too, has changed. If you still want a swapfile, run the following, but only after you have replaced your fly.toml:

rails generate dockerfile --swap=512M
1 Like

Hi rubys, thanks for the quick response!

It’s strange because even if I completely delete the fly.toml file and run

fly config save -a my-secret-app-name

with the newest flyctl version (v0.1.71 linux/amd64) it still generates what I posted above.

Anyway… Is it save for me to just try what you posted without the [[mounts]] section? My app uses the volumes feature for persistent storage.

I tried to figure it out by reading the docs but it is not really clear to me what applies to which version and how you came up with the configuration above? Fly Launch configuration (fly.toml) · Fly Docs

fly config will indeed tell you your current config. What’s happening here is that your current config no longer matches your current dockerfile, so to make them match you will want to make the changes I outlined.

I missed that. Yes, copy your current [[mounts]] section, as is, into the fly.toml I provided.

1 Like

It works! Thank you very much for your help :slight_smile:

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