Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Systemd integration #171

Merged
merged 7 commits into from Apr 3, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Expand Up @@ -86,6 +86,26 @@ server 'example-small.com', roles: [:sidekiq_small]
server 'example-big.com', roles: [:sidekiq_big]
```

## Integration with systemd

Set init system to systemd in the cap deploy config:

```ruby
set :init_system, :systemd
```

Install systemd.service template file and enable the service with:

```
bundle exec cap sidekiq:install
```

Default name for the service file is `sidekiq-stage.service`. This can be changed as needed, for example:

```ruby
set :service_unit_name, "sidekiq-#{fetch(:application)}-#{fetch(:stage)}.service"
```

## Customizing the monit sidekiq templates

If you need change some config in redactor, you can
Expand Down
86 changes: 76 additions & 10 deletions lib/capistrano/tasks/sidekiq.rake
Expand Up @@ -16,6 +16,10 @@ namespace :load do
set :chruby_map_bins, fetch(:chruby_map_bins).to_a.concat(%w{ sidekiq sidekiqctl })
# Bundler integration
set :bundle_bins, fetch(:bundle_bins).to_a.concat(%w(sidekiq sidekiqctl))
# Init system integration
set :init_system, -> { nil }
# systemd integration
set :service_unit_name, "sidekiq-#{fetch(:stage)}.service"
end
end

Expand Down Expand Up @@ -130,10 +134,15 @@ namespace :sidekiq do
task :quiet do
on roles fetch(:sidekiq_role) do |role|
switch_user(role) do
if test("[ -d #{release_path} ]") # fixes #11
for_each_process(true) do |pid_file, idx|
if pid_process_exists?(pid_file)
quiet_sidekiq(pid_file)
case fetch(:init_system)
when :systemd
execute :systemctl, "--user", "reload", fetch(:service_unit_name), raise_on_non_zero_exit: false
else
if test("[ -d #{release_path} ]") # fixes #11
for_each_process(true) do |pid_file, idx|
if pid_process_exists?(pid_file)
quiet_sidekiq(pid_file)
end
end
end
end
Expand All @@ -145,10 +154,15 @@ namespace :sidekiq do
task :stop do
on roles fetch(:sidekiq_role) do |role|
switch_user(role) do
if test("[ -d #{release_path} ]")
for_each_process(true) do |pid_file, idx|
if pid_process_exists?(pid_file)
stop_sidekiq(pid_file)
case fetch(:init_system)
when :systemd
execute :systemctl, "--user", "stop", fetch(:service_unit_name)
else
if test("[ -d #{release_path} ]")
for_each_process(true) do |pid_file, idx|
if pid_process_exists?(pid_file)
stop_sidekiq(pid_file)
end
end
end
end
Expand All @@ -161,8 +175,13 @@ namespace :sidekiq do
task :start do
on roles fetch(:sidekiq_role) do |role|
switch_user(role) do
for_each_process do |pid_file, idx|
start_sidekiq(pid_file, idx) unless pid_process_exists?(pid_file)
case fetch(:init_system)
when :systemd
execute :systemctl, "--user", "start", fetch(:service_unit_name)
else
for_each_process do |pid_file, idx|
start_sidekiq(pid_file, idx) unless pid_process_exists?(pid_file)
end
end
end
end
Expand Down Expand Up @@ -216,6 +235,53 @@ namespace :sidekiq do
end
end

task :install do
on roles fetch(:sidekiq_role) do |role|
switch_user(role) do
case fetch(:init_system)
when :systemd
create_systemd_template
execute :systemctl, "--user", "enable", fetch(:service_unit_name)
end
end
end
end

task :uninstall do
on roles fetch(:sidekiq_role) do |role|
switch_user(role) do
case fetch(:init_system)
when :systemd
execute :systemctl, "--user", "disable", fetch(:service_unit_name)
execute :rm, File.join(fetch(:service_unit_path, fetch_systemd_unit_path),fetch(:service_unit_name))
end
end
end
end

def fetch_systemd_unit_path
home_dir = capture :pwd
File.join(home_dir, ".config", "systemd", "user")
end

def create_systemd_template
search_paths = [
File.expand_path(
File.join(*%w[.. .. .. generators capistrano sidekiq systemd templates sidekiq.service.capistrano.erb]),
__FILE__
),
]
template_path = search_paths.detect {|path| File.file?(path)}
template = File.read(template_path)
systemd_path = fetch(:service_unit_path, fetch_systemd_unit_path)
execute :mkdir, "-p", systemd_path
upload!(
StringIO.new(ERB.new(template).result(binding)),
"#{systemd_path}/#{fetch :service_unit_name}"
)
execute :systemctl, "--user", "daemon-reload"
end

def switch_user(role, &block)
su_user = sidekiq_user(role)
if su_user == role.user
Expand Down
@@ -0,0 +1,19 @@
[Unit]
Description=sidekiq for <%= "#{fetch(:application)} (#{fetch(:stage)})" %>
After=syslog.target network.target

[Service]
Type=simple
Environment=RAILS_ENV=<%= fetch(:rails_env) %>
WorkingDirectory=<%= fetch(:deploy_to) %>/current
ExecStart=<%= fetch(:bundler_path, '/usr/local/bin/bundler') %> exec sidekiq -e <%= fetch(:rails_env) %>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert on systemd, but it seems that ExecStart is not taking into consideration sidekiq.yml config file, right? Since this is oficially supported by the gem via the set :sidekiq_config option (see https://github.com/seuros/capistrano-sidekiq/wiki), I think it should be supported here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean? This just call bundle exec sidekiq via systemd, it should be some sort of an equivalent to cap sidekiq:start. Nothing less, nothing more.

I have an idea to add a generator for this file, which can solve some issue. In the mean time, this is just a template for a service file and you can customize the resulting systemd service file to your liking.

ExecReload=/bin/kill -USR1 $MAINPID

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this should be ExecReload=/bin/kill -TSTP $MAINPID (TSTP instead of USR1) for Sidekiq 5. https://github.com/mperham/sidekiq/wiki/Signals#tstp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

ExecStop=/bin/kill -TERM $MAINPID

RestartSec=1
Restart=on-failure

SyslogIdentifier=sidekiq

[Install]
WantedBy=default.target