From bb20e8e2bde0b36487cb36f182c3ddbcc16488d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 1 Feb 2024 14:25:42 +0100 Subject: [PATCH 1/2] Disable ExecJS when running Puma and Delayed Job By default, when starting a Rails application, ExecJS checks whether there's a runtime available in the system. Since on production we now use FNM to manage node versions, this meant that we had to run Puma using the `fnm exec bundle exec puma` command. However, this causes issues when integrating Puma with Systemd. For instance, when using `fnm exec`, the PID for the main process is no longer the Puma process but the FNM process, meaning that stopping and restarting Puma will no longer behave as expected and might last 90 seconds (Systemd's timeout to stop a service). Furthermore, using a Puma Systemd socket in order to implement hot or phased restarts won't work either, and so we'll get 502 errors while restarting the service. So we're using the `EXECJS_RUNTIME=Disabled` environment variable in the Systemd service, which means we can remove the `fnm exec` prefix in the ExecStart command (which starts Puma) and now the PID for the main process is the Puma process, stopping/restarting the service no longer times out, and we'll be able to implement Puma socket activation and hot restarts. However, removing `bundle` from the list of commands which use `fnm exec` (the `fnm_map_bins`) meant that we got a `RuntimeUnavailable` exception when running `bundle exec bin/delayed_job`. We tried to add `delayed_job` to the `fnm_map_bins` variable but couldn't make it work. Since we only need the ExecJs runtime when precompiling the assets but we don't need it in order to start Puma or Delayed Job, we're adding `{ EXECJS_RUNTIME: "Disabled" }` to Capistrano's default environment and we're only using the default Runtime when `fnm exec` is used, which we've done by setting the environment variable in the prefix of the fnm command. This way, when running `EXECJS_RUNTIME='' fnm exec bundle exec rake assets:precompile`, the right ExecJS Runtime will be loaded, but it won't be loaded (since it isn't needed) when starting Puma or Delayed Job. --- config/deploy.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/deploy.rb b/config/deploy.rb index 2aa6237bc..5e4771e6b 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -15,6 +15,7 @@ def main_deploy_server end set :rails_env, fetch(:stage) +set :default_env, { EXECJS_RUNTIME: "Disabled" } set :rvm1_map_bins, -> { fetch(:rvm_map_bins).to_a.concat(%w[rake gem bundle ruby]).uniq } set :application, deploysecret(:app_name, default: "consul") @@ -46,10 +47,11 @@ set :fnm_setup_command, -> do "cd #{release_path} && fnm env > /dev/null && eval \"$(fnm env)\"" end set :fnm_install_node_command, -> { "#{fetch(:fnm_setup_command)} && fnm use --install-if-missing" } -set :fnm_map_bins, %w[bundle node npm puma pumactl rake yarn] +set :fnm_map_bins, %w[node npm rake yarn] set :puma_conf, "#{release_path}/config/puma/#{fetch(:rails_env)}.rb" set :puma_systemctl_user, :user +set :puma_service_unit_env_vars, ["EXECJS_RUNTIME=Disabled"] set :delayed_job_workers, 2 set :delayed_job_roles, :background @@ -123,7 +125,7 @@ task :map_node_bins do on roles(:app) do within release_path do with rails_env: fetch(:rails_env) do - prefix = -> { "#{fetch(:fnm_path)}/fnm exec" } + prefix = -> { "EXECJS_RUNTIME='' #{fetch(:fnm_path)}/fnm exec" } fetch(:fnm_map_bins).each do |command| SSHKit.config.command_map.prefix[command.to_sym].unshift(prefix) From 1d9d467c863920a8120d8a451389e4a6d6e6291e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sen=C3=A9n=20Rodero=20Rodr=C3=ADguez?= Date: Thu, 1 Feb 2024 14:26:15 +0100 Subject: [PATCH 2/2] Enable puma socket activation This gives us graceful restarts --- config/deploy.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/deploy.rb b/config/deploy.rb index 5e4771e6b..619c0a876 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -51,6 +51,7 @@ set :fnm_map_bins, %w[node npm rake yarn] set :puma_conf, "#{release_path}/config/puma/#{fetch(:rails_env)}.rb" set :puma_systemctl_user, :user +set :puma_enable_socket_service, true set :puma_service_unit_env_vars, ["EXECJS_RUNTIME=Disabled"] set :delayed_job_workers, 2