New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

capistrano-systemd-ng

Package Overview
Dependencies
Maintainers
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

capistrano-systemd-ng

  • 0.1.4
  • Rubygems
  • Socket score

Version published
Maintainers
2
Created
Source

capistrano-systemd-ng

Gem Version CI

This gem adds capistrano tasks to control multiple services with systemd. This gem supports capistrano > 3.17.0.

Installation

Add this line to your application's Gemfile:

gem 'capistrano-systemd-ng', require: false

And then execute:

$ bundle

Or install it yourself as:

$ gem install capistrano-systemd-ng

Usage

Please activate the Capistrano approle in config/deploy/staging.rband/or config/deploy/production.rb:

 role :app, %w{deploy@example.com}

Replace example.com by the domain name used by your server.

And add these lines to your Capfile:

require "capistrano/systemd/multiservice"
install_plugin Capistrano::Systemd::MultiService.new_service("example1")
install_plugin Capistrano::Systemd::MultiService.new_service("example2")

And put config/systemd/example1.service.erb (and config/systemd/example2.service.erb, ...) like this:

[Unit]
Description = <%= fetch(:application) %> application server example1

[Service]
Environment = RAILS_ENV=<%= fetch(:rails_env) %>
Environment = PWD=<%= current_path %>
WorkingDirectory = <%= current_path %>
ExecStart = bundle exec some-application-server start
User = exampleuser
Group = examplegroup

[Install]
WantedBy = multi-user.target
  • see systemd.service(5) for details
  • when :application is set to foo, this file will be installed as foo_example1.service (and foo_example2.service, ...)

And add these lines to config/deploy.rb if you want to reload/restart services on deploy:

after 'deploy:publishing', 'systemd:example1:restart'
after 'deploy:publishing', 'systemd:example2:reload-or-restart'

And then deploy.

# Upload and install systemd service unit files before deploy
cap STAGE systemd:example1:setup systemd:example2:setup

# Deploy as usual
cap STAGE deploy

User services

To have the service installed under your own user rather than root

require "capistrano/systemd/multiservice"
install_plugin Capistrano::Systemd::MultiService.new_service("example1", service_type: 'user')
install_plugin Capistrano::Systemd::MultiService.new_service("example2", service_type: 'user')

If using the user service type services will be installed in your users home directory under /.config/systemd/user. Systemd commands on those services can be run by passing a --user flag, e.g. systemctl --user list-unit-files Nothing else in setup should require change and Capistrano tasks should remain the same as when installing system services.

Example of user service in config/systemd/passenger.service.erb:

[Unit]
Description=Passenger Standalone Application Server for <%= fetch(:application) %>
After=network.target

[Service]
Type=forking
Environment=RAILS_ENV=<%= fetch(:rails_env) %>
Environment=PWD=<%= current_path %>
WorkingDirectory=<%= current_path %>
PIDFile=/run/passenger/devopsy.pid
ExecStart=/home/deploy/.asdf/bin/asdf exec bundle exec passenger start -d --pid-file /run/passenger/devopsy.pid -e production -p 3002 --instance-registry-dir /run/passenger
ExecStop=/home/deploy/.asdf/bin/asdf exec bundle exec passenger stop --pid-file /run/passenger/devopsy.pid
PrivateTmp=yes

[Install]
WantedBy=default.target

For user services, the target should be default.target, not multi-user.target. And no User or Group should be mentioned to avoid errors.

It is in config/deploy.rb that you should have the user set, and for that example:

set :user, "deploy"
after 'deploy:publishing', 'systemd:passenger:restart'

And in the Capfile, you should have these:

require "capistrano/systemd/multiservice"
install_plugin Capistrano::Systemd::MultiService.new_service("passenger", service_type: "user")

Capistrano Tasks

With install_plugin Capistrano::Systemd::MultiService.new_service("example1"), following tasks are defined.

  • systemd:example1:setup
  • systemd:example1:remove
  • systemd:example1:validate
  • systemd:example1:daemon-reload
  • systemd:example1:start
  • systemd:example1:stop
  • systemd:example1:reload
  • systemd:example1:restart
  • systemd:example1:reload-or-restart
  • systemd:example1:enable
  • systemd:example1:disable

See lib/capistrano/tasks/systemd/multiservice/system_service.rake, lib/capistrano/systemd/multiservice/system_service.rb for details.

Configuration Variables

With install_plugin Capistrano::Systemd::MultiService.new_service("example1"), following Configuration variables are defined.

  • :systemd_example1_role
  • :systemd_example1_units_src
  • :systemd_example1_units_dir
  • :systemd_example1_units_dest
  • :systemd_example1_instances
  • :systemd_example1_service
  • :systemd_example1_instance_services

See lib/capistrano/systemd/multiservice/system_service.rb for details.

Examples

Rails application with unicorn and delayed_job

Capfile
## ...snip...

require 'capistrano/systemd/multiservice'
install_plugin Capistrano::Systemd::MultiService.new_service('unicorn')
install_plugin Capistrano::Systemd::MultiService.new_service('delayed_job')

## ...snip...
config/deploy.rb
## ...snip...

set :application, 'foo'

## ...snip...

set :systemd_delayed_job_instances, ->{ 3.times.to_a }

after 'deploy:restart', 'systemd:unicorn:reload-or-restart'
after 'deploy:restart', 'systemd:delayed_job:restart'

after 'deploy:publishing', 'deploy:restart'

## ...snip...
config/systemd/unicorn.service.erb

This file will be installed as foo_unicorn.service.

[Unit]
Description = <%= fetch(:application) %> unicorn rack server

[Service]
Environment = PATH=<%= fetch(:rbenv_path) %>/shims:/usr/local/bin:/usr/bin:/bin
Environment = RBENV_VERSION=<%= fetch(:rbenv_ruby) %>
Environment = RBENV_ROOT=<%= fetch(:rbenv_path) %>
Environment = RAILS_ENV=<%= fetch(:rails_env) %>
Environment = PWD=<%= current_path %>

WorkingDirectory = <%= current_path %>

ExecStart = <%= fetch(:rbenv_path) %>/bin/rbenv exec bundle exec unicorn -c <%= current_path %>/config/unicorn.rb
ExecReload = /bin/kill -USR2 $MAINPID

PIDFile = <%= shared_path %>/tmp/pids/unicorn.pid
KillSignal = SIGQUIT
KillMode = process
TimeoutStopSec = 62
Restart = always

User = app-user
Group = app-group

[Install]
WantedBy = multi-user.target
config/systemd/delayed_job.service.erb

This file will be installed as foo_delayed_job.service.

[Unit]
Description = <%= fetch(:application) %> delayed_job
Requires = <%= fetch(:"#{prefix}_instance_services").join(" ") %>

[Service]
Type = oneshot
RemainAfterExit = yes
ExecStart  = /bin/true
ExecReload = /bin/true

[Install]
WantedBy = multi-user.target
config/systemd/delayed_job@.service.erb

This file will be installed as foo_delayed_job@.service, and creates 3 instanced service units foo_delayed_job@0.service, foo_delayed_job@1.service, foo_delayed_job@2.service because :systemd_delayed_job_instances is set to ->{ 3.times.to_a } in config/deploy.rb.

[Unit]
Description = <%= fetch(:application) %> delayed_job (instance %i)
PartOf = <%= fetch(:"#{prefix}_service") %>
ReloadPropagatedFrom = <%= fetch(:"#{prefix}_service") %>

[Service]
Type = forking

Environment = PATH=<%= fetch(:rbenv_path) %>/shims:/usr/local/bin:/usr/bin:/bin
Environment = RBENV_VERSION=<%= fetch(:rbenv_ruby) %>
Environment = RBENV_ROOT=<%= fetch(:rbenv_path) %>
Environment = RAILS_ENV=<%= fetch(:rails_env) %>
Environment = PWD=<%= current_path %>

WorkingDirectory = <%= current_path %>

ExecStart  = <%= fetch(:rbenv_path) %>/bin/rbenv exec bundle exec bin/delayed_job -p <%= fetch(:application) %> -i %i start
ExecStop   = <%= fetch(:rbenv_path) %>/bin/rbenv exec bundle exec bin/delayed_job -p <%= fetch(:application) %> -i %i stop
ExecReload = /bin/kill -HUP $MAINPID

PIDFile = <%= shared_path %>/tmp/pids/delayed_job.%i.pid
TimeoutStopSec = 22
Restart = always

User = app-user
Group = app-group

[Install]
WantedBy = multi-user.target
config/unicorn.rb
shared_path = "/path/to/shared"

worker_processes   5
listen             "#{shared_path}/tmp/sockets/unicorn.sock"
pid                "#{shared_path}/tmp/pids/unicorn.pid"
stderr_path        "#{shared_path}/log/unicorn_stderr.log"
stdout_path        "#{shared_path}/log/unicorn_stdout.log"
preload_app        true

before_exec do |server|
  ENV["BUNDLE_GEMFILE"] = "/path/to/current/Gemfile"
end

before_fork do |server, worker|
  if defined? ActiveRecord::Base
    ActiveRecord::Base.connection.disconnect!
  end

  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end

  sleep 1
end

after_fork do |server, worker|
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end
end
Commands to setup systemd services and deploy
# Upload and install systemd service unit files before deploy
cap STAGE systemd:unicorn:setup systemd:delayed_job:setup

# Deploy as usual
cap STAGE deploy

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/HLFH/capistrano-systemd-ng.

FAQs

Package last updated on 23 Jun 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc