diff --git a/CHANGELOG.md b/CHANGELOG.md index 1059be3..879647c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ ## [Unreleased] +- Make systemd unit environment variables configurable via + `:solid_queue_service_unit_env_files` and `:solid_queue_service_unit_env_vars` + (inspired by `capistrano-sidekiq`). Both fall back to shared + `:service_unit_env_files` / `:service_unit_env_vars` when set. +- Make the executed command configurable via `:solid_queue_command` + (default: `"rake solid_queue:start"`) so SolidQueue >= 0.4 setups can use + `"bin/jobs"`. +- Fix: `[Install] WantedBy=` now switches to `multi-user.target` when running + in `:system` mode (previously always `default.target`, which prevented boot + activation of system units). +- Fix: in `:system` mode the service now runs as `:solid_queue_user` + (defaults to `:run_as` → `:user`) instead of implicitly running as root. +- **Breaking**: Capistrano's `default_env` is no longer rendered into the + systemd unit file. `MALLOC_ARENA_MAX=2` is no longer hardcoded either. Pass + what you need explicitly via the new configuration hooks. `RAILS_ENV` is + still set from the current stage. + ## [0.1.2] - 2025-06-12 - Quiet task only runs on :solid_queue_role [#3](https://github.com/codeur/capistrano-solid_queue/pull/5) by [@bashcoder](https://github.com/bashcoder) diff --git a/README.md b/README.md index 676f0f7..d0c97a4 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,56 @@ through their Capistrano counterparts, ex: `bundle exec cap solid_queue:restart` The plugin has registered a Capistrano `hook` to run `bundle exec cap solid_queue:restart` after deploy. See [`#register_hooks`](lib/capistrano/solid_queue.rb) +## Configuration + +The following variables can be set in your `deploy.rb` or stage files: + +```ruby +set :solid_queue_role, :app +set :solid_queue_access_log, -> { File.join(shared_path, "log", "solid_queue.log") } +set :solid_queue_error_log, -> { File.join(shared_path, "log", "solid_queue.log") } +set :solid_queue_service_unit_name, -> { "#{fetch(:application)}_solid_queue_#{fetch(:stage)}" } +set :solid_queue_systemctl_user, :user # or :system + +# What runs after `bundle exec` — override for SolidQueue >= 0.4: +set :solid_queue_command, "bin/jobs" + +# Unix user for the service when running in :system mode +# (defaults to :run_as, then to Capistrano's :user) +set :solid_queue_user, "deploy" +``` + +### Environment variables + +Two hooks let you inject arbitrary environment into the generated systemd unit +(inspired by [`capistrano-sidekiq`](https://github.com/seuros/capistrano-sidekiq)): + +```ruby +# Referenced via `EnvironmentFile=` — one line per file +set :solid_queue_service_unit_env_files, %w[ + /etc/environment + /home/deploy/apps/my_app/shared/.env +] + +# Rendered as `Environment="KEY=VALUE"` — one line per entry +set :solid_queue_service_unit_env_vars, [ + "RAILS_LOG_TO_STDOUT=1", + "DB_POOL=10", + "SOLID_QUEUE_IN_PUMA=false" +] +``` + +If your project already sets `:service_unit_env_files` / `:service_unit_env_vars` +(shared with other systemd-based capistrano plugins), they are picked up as +the default — you only need to override when SolidQueue should see a different +set of variables. + +Only `RAILS_ENV=` is set implicitly (it is derived directly from the +Capistrano stage). Capistrano's `default_env` is **not** rendered into the unit +file — pass anything else you need (including tuning knobs like +`MALLOC_ARENA_MAX`) via `:solid_queue_service_unit_env_vars` or +`:solid_queue_service_unit_env_files`. + ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. diff --git a/lib/capistrano/solid_queue.rb b/lib/capistrano/solid_queue.rb index 3235d12..16b91d3 100644 --- a/lib/capistrano/solid_queue.rb +++ b/lib/capistrano/solid_queue.rb @@ -11,6 +11,19 @@ def set_defaults set_if_empty :solid_queue_error_log, -> { File.join(shared_path, "log", "solid_queue.log") } set_if_empty :solid_queue_service_unit_name, -> { "#{fetch(:application)}_solid_queue_#{fetch(:stage)}" } set_if_empty :solid_queue_systemd_conf_dir, -> { fetch_systemd_unit_path } + + # Command executed by the systemd unit (concatenated after `bundle exec`). + # Override with e.g. "bin/jobs" for SolidQueue >= 0.4 setups. + set_if_empty :solid_queue_command, "rake solid_queue:start" + + # Unix user the service runs as when using `:system` mode. Falls back to + # `:run_as` (shared with other systemd capistrano plugins) and finally + # the SSH `:user` capistrano connects with. + set_if_empty :solid_queue_user, -> { fetch(:run_as, fetch(:user)) } + + # SolidQueue could have a stripped down or more complex version of the environment variables + set_if_empty :solid_queue_service_unit_env_files, -> { fetch(:service_unit_env_files, []) } + set_if_empty :solid_queue_service_unit_env_vars, -> { fetch(:service_unit_env_vars, []) } end def define_tasks diff --git a/lib/capistrano/templates/solid_queue.service.erb b/lib/capistrano/templates/solid_queue.service.erb index 190fd16..ae9c601 100644 --- a/lib/capistrano/templates/solid_queue.service.erb +++ b/lib/capistrano/templates/solid_queue.service.erb @@ -1,18 +1,21 @@ [Unit] -Description=SolidQueue background job +Description=SolidQueue background job for <%= "#{fetch(:application)} (#{fetch(:stage)})" %> After=syslog.target network.target [Service] Type=simple -Environment='RAILS_ENV=<%= fetch(:stage) %>' -<% fetch(:default_env).reject{ |k, _| k.to_s == 'path' }.each do |variable, value| -%> -Environment='<%= variable.to_s.upcase %>=<%= value.to_s %>' +<%= "User=#{fetch(:solid_queue_user)}" if fetch(:solid_queue_systemctl_user) == :system %> +Environment=RAILS_ENV=<%= fetch(:stage) %> +<% Array(fetch(:solid_queue_service_unit_env_files)).each do |file| -%> +EnvironmentFile=<%= file %> +<% end -%> +<% Array(fetch(:solid_queue_service_unit_env_vars)).each do |environment_variable| -%> +Environment="<%= environment_variable %>" <% end -%> WorkingDirectory=<%= current_path %> -ExecStart=<%= capture(:echo, SSHKit.config.command_map[:bundle]).strip %> exec rake solid_queue:start +ExecStart=<%= capture(:echo, SSHKit.config.command_map[:bundle]).strip %> exec <%= fetch(:solid_queue_command) %> ExecReload=/bin/kill -TSTP $MAINPID ExecStop=/bin/kill -TERM $MAINPID -Environment=MALLOC_ARENA_MAX=2 # if we crash, restart RestartSec=1 @@ -24,4 +27,4 @@ Restart=on-failure SyslogIdentifier=<%= fetch(:solid_queue_service_unit_name) %> [Install] -WantedBy=default.target +WantedBy=<%= fetch(:solid_queue_systemctl_user) == :system ? "multi-user.target" : "default.target" %>