capistrano-sidekiq-systemd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cf9409c23a84e7e446cff8abd4b7f30188cb9fa6d6f2443815ae97200bbb3967
4
+ data.tar.gz: d88865d20c429021fd362137c74bb9f6a28939ba1746f917970776aeb6dcd13b
5
+ SHA512:
6
+ metadata.gz: e831e9e88f1e165b52156f084f8e986adf4c3ab394526befb10af9fcbe6d95adc9b2cb6a69dc2a9b301c107ca65daa89837a1099a2180b929125542b499b4185
7
+ data.tar.gz: 74b8ca37c76cf6a93098fb112958f92ed2a69dcd2af48c0e66180df8ea27b697e068da06a7c42294c26058be6ebaf6afbba32b1a0ee3f9ad12a689f5ffde2038
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.5
7
+ before_install: gem install bundler -v 1.17.3
@@ -0,0 +1,4 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+ - Syestem db .service template for multiple processes
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at lyoshakr@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in capistrano-sidekiq-systemd.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 spilin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,193 @@
1
+ # Capistrano::Sidekiq::Systemd
2
+
3
+ Sidekiq integration for Capistrano(`systemd` only).
4
+ Heavily influenced by https://github.com/seuros/capistrano-sidekiq.
5
+ Supports Multiple processes. Primarity should work on sidekiq version > 6.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'capistrano-sidekiq-systemd', require: false
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install capistrano-sidekiq-systemd
22
+
23
+ ## Usage
24
+ ```ruby
25
+ # Capfile
26
+ require 'capistrano/sidekiq/systemd'
27
+ require 'capistrano/sidekiq/monit' #to require monit tasks
28
+ ```
29
+ Configurable options, shown here with defaults:
30
+
31
+ ```ruby
32
+ set :sidekiq_default_hooks, true
33
+ set :sidekiq_env, -> { fetch(:rack_env, fetch(:rails_env, fetch(:stage))) }
34
+ set :sidekiq_roles, fetch(:sidekiq_role, :app)
35
+ set :sidekiq_options_per_process, nil
36
+ set :sidekiq_user, nil
37
+ set :sidekiq_max_mem, nil
38
+ set :service_unit_name, "sidekiq-#{fetch(:stage)}.service"
39
+ # Rbenv, Chruby, and RVM integration
40
+ set :rbenv_map_bins, fetch(:rbenv_map_bins).to_a.concat(%w[sidekiq])
41
+ set :rvm_map_bins, fetch(:rvm_map_bins).to_a.concat(%w[sidekiq])
42
+ set :chruby_map_bins, fetch(:chruby_map_bins).to_a.concat(%w[sidekiq])
43
+ # Bundler integration
44
+ set :bundle_bins, fetch(:bundle_bins).to_a.concat(%w[sidekiq])
45
+ # Options for single process setup
46
+ set :sidekiq_require, nil
47
+ set :sidekiq_tag, nil
48
+ set :sidekiq_queue, nil
49
+ set :sidekiq_config, nil
50
+ set :sidekiq_concurrency, nil
51
+ set :sidekiq_options, nil
52
+ # Monit options
53
+ set :sidekiq_monit_conf_dir, '/etc/monit/conf.d'
54
+ set :sidekiq_monit_conf_file, "sidekiq-#{fetch(:stage)}.conf"
55
+ set :sidekiq_monit_use_sudo, true
56
+ set :sidekiq_monit_max_mem, nil
57
+ set :monit_bin, '/usr/bin/monit'
58
+ set :sidekiq_monit_default_hooks, true
59
+ set :sidekiq_monit_group, nil
60
+ ```
61
+
62
+ ## Tasks
63
+
64
+ cap sidekiq:install # Generate and upload .service files
65
+ cap sidekiq:quiet # Quiet sidekiq (stop fetching new tasks from Redis)
66
+ cap sidekiq:restart # Restart sidekiq
67
+ cap sidekiq:start # Start sidekiq
68
+ cap sidekiq:stop # Stop sidekiq
69
+ cap sidekiq:monit:install # Generate and upload monit.conf file
70
+ cap sidekiq:monit:monitor # Monitor Sidekiq monit-service
71
+ cap sidekiq:monit:restart # Restart Sidekiq monit-service
72
+ cap sidekiq:monit:start # Start Sidekiq monit-service
73
+ cap sidekiq:monit:stop # Stop Sidekiq monit-service
74
+ cap sidekiq:monit:uninstall # Uninstall Sidekiq monit-service
75
+ cap sidekiq:monit:unmonitor # Unmonitor Sidekiq monit-service
76
+
77
+ ## Default hooks(systemd)
78
+
79
+ after 'deploy:starting', 'sidekiq:quiet'
80
+ after 'deploy:updated', 'sidekiq:stop'
81
+ after 'deploy:published', 'sidekiq:start'
82
+ after 'deploy:failed', 'sidekiq:restart'
83
+
84
+ By default all of these hooks are active. If you wish to remove them please set:
85
+
86
+ ```ruby
87
+ set :sidekiq_default_hooks, false
88
+ ```
89
+
90
+ ## Default hooks(monit)
91
+
92
+ before 'deploy:updating', 'sidekiq:monit:unmonitor'
93
+ after 'deploy:published', 'sidekiq:monit:monitor'
94
+
95
+ By default all of these hooks are active. If you wish to remove them please set:
96
+
97
+ ```ruby
98
+ set :sidekiq_monit_default_hooks, false
99
+ ```
100
+
101
+
102
+ ## Multiple processes
103
+
104
+ You can configure sidekiq to start with multiple processes. To configure each process please use `sidekiq_options_per_process`.
105
+ Example using different config files:
106
+
107
+ ```ruby
108
+ set :sidekiq_options_per_process, [
109
+ "--config config/sidekiq.yml",
110
+ "--config config/sidekiq.yml",
111
+ "--config config/sidekiq_mailer.yml"
112
+ ]
113
+ ```
114
+
115
+ Example using arbitrary options:
116
+
117
+ ```ruby
118
+ set :sidekiq_options_per_process, [
119
+ "--queue high --concurrency 2",
120
+ "--queue default --concurrency 4 ",
121
+ ]
122
+ ```
123
+
124
+ Example using hash options and custom service_unit_name(Though it's not recommended to change `service_unit_name`):
125
+
126
+ ```ruby
127
+ set :sidekiq_options_per_process, [
128
+ { queue: 'high', concurrency: 2, service_unit_name: 'sidekiq-production-1' }
129
+ { queue: 'default', concurrency: 4, service_unit_name: 'sidekiq-production-2' }
130
+ ]
131
+ ```
132
+
133
+ `Important!`
134
+ Please do not change `--tag` option if you want to use `monit` integration. By default it will be set to uniq `service_unit_name`, so monit will be able to identify sidekiq process.
135
+
136
+ ## Memory limit(monit)
137
+ You can set memory limit for monit
138
+ ```ruby
139
+ set :sidekiq_monit_max_mem, 3072
140
+ ```
141
+ This will add `if totalmem is greater than 3072 MB for 2 cycles then restart` to monit.conf file. Don't forget to run `cap sidekiq:monit:install` any time you change `sidekiq_monit_max_mem` option.
142
+
143
+ ## Memory limit(systemd)
144
+ There is an available option to set up memory limit for systemd.service:
145
+
146
+ You can set memory limit with:
147
+ ```ruby
148
+ set :sidekiq_max_mem, '3072K'
149
+ ```
150
+ This will add:
151
+
152
+ MemoryAccounting=true
153
+ MemoryLimit=3072K
154
+
155
+ Though i am not able to get it to work because we use `--user` to control systemd. TODO: Investigate.
156
+
157
+
158
+ ## Configuring systemd
159
+ To generate and upload `.service` file please run:
160
+
161
+ cap sidekiq:install
162
+
163
+ ## Configuring monit
164
+ To generate and upload `.conf` file please run:
165
+
166
+ cap sidekiq:monit:install
167
+
168
+ Please remember to add `require` to `Capfile`
169
+
170
+ ```ruby
171
+ require 'capistrano/sidekiq/monit' #to require monit tasks
172
+ ```
173
+
174
+ If your deploy user has no need in `sudo` for using monit, you can disable it as follows:
175
+
176
+ ```ruby
177
+ set :sidekiq_monit_use_sudo, false
178
+ ```
179
+ ## Development
180
+
181
+ 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](https://rubygems.org).
182
+
183
+ ## Contributing
184
+
185
+ Bug reports and pull requests are welcome on GitHub at https://github.com/spilin/capistrano-sidekiq-systemd. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
186
+
187
+ ## License
188
+
189
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
190
+
191
+ ## Code of Conduct
192
+
193
+ Everyone interacting in the Capistrano::Sidekiq::Systemd project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/spilin/capistrano-sidekiq-systemd/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "capistrano/sidekiq/systemd"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "capistrano/sidekiq/systemd/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capistrano-sidekiq-systemd"
8
+ spec.version = Capistrano::Sidekiq::Systemd::VERSION
9
+ spec.authors = ["spilin"]
10
+ spec.email = ["lyoshakr@gmail.com"]
11
+
12
+ spec.summary = "Capistrano sidekiq systemd support"
13
+ spec.description = "Capistrano sidekiq systemd support. Allows to deploy multiple processes."
14
+ spec.homepage = 'https://github.com/spilin/capistrano-sidekiq-systemd'
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = "https://github.com/spilin/capistrano-sidekiq-systemd"
22
+ spec.metadata["changelog_uri"] = "https://github.com/spilin/capistrano-sidekiq-systemd/CHANGELOG.md"
23
+ else
24
+ raise "RubyGems 2.0 or newer is required to protect against " \
25
+ "public gem pushes."
26
+ end
27
+
28
+ # Specify which files should be added to the gem when it is released.
29
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_dependency 'capistrano', '>= 3.9.0'
38
+ end
@@ -0,0 +1 @@
1
+ load File.expand_path('../tasks/monit.rake', __FILE__)
@@ -0,0 +1 @@
1
+ load File.expand_path('../tasks/systemd.rake', __FILE__)
@@ -0,0 +1,7 @@
1
+ module Capistrano
2
+ module Sidekiq
3
+ module Systemd
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,107 @@
1
+ namespace :load do
2
+ task :defaults do
3
+ set :sidekiq_monit_conf_dir, '/etc/monit/conf.d'
4
+ set :sidekiq_monit_conf_file, "sidekiq-#{fetch(:stage)}.conf"
5
+ set :sidekiq_monit_use_sudo, true
6
+ set :monit_bin, '/usr/bin/monit'
7
+ set :sidekiq_monit_default_hooks, true
8
+ set :sidekiq_monit_group, nil
9
+ end
10
+ end
11
+
12
+ namespace :deploy do
13
+ before :starting, :check_sidekiq_monit_hooks do
14
+ if fetch(:sidekiq_default_hooks) && fetch(:sidekiq_monit_default_hooks)
15
+ invoke 'sidekiq:monit:add_default_hooks'
16
+ end
17
+ end
18
+ end
19
+
20
+ namespace :sidekiq do
21
+ namespace :monit do
22
+ task :add_default_hooks do
23
+ before 'deploy:updating', 'sidekiq:monit:unmonitor'
24
+ after 'deploy:published', 'sidekiq:monit:monitor'
25
+ end
26
+
27
+ desc 'Stop Sidekiq monit-service'
28
+ task :stop do
29
+ on roles(fetch(:sidekiq_roles)) do
30
+ sidekiq_options_per_process.each_index do |index|
31
+ sudo_if_needed "#{fetch(:monit_bin)} stop #{service_unit_name(index)}"
32
+ end
33
+ end
34
+ end
35
+
36
+ desc 'Start Sidekiq monit-service'
37
+ task :start do
38
+ on roles(fetch(:sidekiq_roles)) do
39
+ sidekiq_options_per_process.each_index do |index|
40
+ sudo_if_needed "#{fetch(:monit_bin)} start #{service_unit_name(index)}"
41
+ end
42
+ end
43
+ end
44
+
45
+ desc 'Restart Sidekiq monit-service'
46
+ task :restart do
47
+ on roles(fetch(:sidekiq_roles)) do
48
+ sidekiq_options_per_process.each_index do |index|
49
+ sudo_if_needed"#{fetch(:monit_bin)} restart #{service_unit_name(index)}"
50
+ end
51
+ end
52
+ end
53
+
54
+ desc 'Unmonitor Sidekiq monit-service'
55
+ task :unmonitor do
56
+ on roles(fetch(:sidekiq_roles)) do
57
+ sidekiq_options_per_process.each_index do |index|
58
+ begin
59
+ sudo_if_needed "#{fetch(:monit_bin)} unmonitor #{service_unit_name(index)}"
60
+ rescue
61
+ # no worries here
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ desc 'Monitor Sidekiq monit-service'
68
+ task :monitor do
69
+ on roles(fetch(:sidekiq_roles)) do
70
+ sidekiq_options_per_process.each_index do |index|
71
+ begin
72
+ sudo_if_needed "#{fetch(:monit_bin)} monitor #{service_unit_name(index)}"
73
+ rescue
74
+ invoke 'sidekiq:monit:install'
75
+ sudo_if_needed "#{fetch(:monit_bin)} monitor #{service_unit_name(index)}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ desc 'Install Sidekiq monit-service'
82
+ task :install do
83
+ on roles(fetch(:sidekiq_roles)) do |role|
84
+ template = File.read(File.expand_path('../../../../generators/capistrano/sidekiq/monit/templates/sidekiq.conf.capistrano.erb', __FILE__))
85
+ upload!(StringIO.new(ERB.new(template).result(binding)), "#{fetch(:tmp_dir)}/monit.conf")
86
+ sudo_if_needed "mv #{fetch(:tmp_dir)}/monit.conf #{fetch(:sidekiq_monit_conf_dir)}/#{fetch(:sidekiq_monit_conf_file)}"
87
+ sudo_if_needed "#{fetch(:monit_bin)} reload"
88
+ end
89
+ end
90
+
91
+ desc 'Uninstall Sidekiq monit-service'
92
+ task :uninstall do
93
+ on roles(fetch(:sidekiq_roles)) do |role|
94
+ sudo_if_needed "rm #{fetch(:sidekiq_monit_conf_dir)}/#{fetch(:sidekiq_monit_conf_file)}"
95
+ sudo_if_needed "#{fetch(:monit_bin)} reload"
96
+ end
97
+ end
98
+
99
+ def sudo_if_needed(command)
100
+ send(use_sudo? ? :sudo : :execute, command)
101
+ end
102
+
103
+ def use_sudo?
104
+ fetch(:sidekiq_monit_use_sudo)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,189 @@
1
+ namespace :load do
2
+ task :defaults do
3
+ set :sidekiq_default_hooks, true
4
+ set :sidekiq_env, -> { fetch(:rack_env, fetch(:rails_env, fetch(:stage))) }
5
+ set :sidekiq_roles, fetch(:sidekiq_role, :app)
6
+ set :sidekiq_options_per_process, nil
7
+ set :sidekiq_user, nil
8
+ set :sidekiq_max_mem, nil
9
+ set :service_unit_name, "sidekiq-#{fetch(:stage)}.service"
10
+ # Rbenv, Chruby, and RVM integration
11
+ set :rbenv_map_bins, fetch(:rbenv_map_bins).to_a.concat(%w[sidekiq])
12
+ set :rvm_map_bins, fetch(:rvm_map_bins).to_a.concat(%w[sidekiq])
13
+ set :chruby_map_bins, fetch(:chruby_map_bins).to_a.concat(%w[sidekiq])
14
+ # Bundler integration
15
+ set :bundle_bins, fetch(:bundle_bins).to_a.concat(%w[sidekiq])
16
+ # Options for single process setup
17
+ set :sidekiq_require, nil
18
+ set :sidekiq_tag, nil
19
+ set :sidekiq_queue, nil
20
+ set :sidekiq_config, nil
21
+ set :sidekiq_concurrency, nil
22
+ set :sidekiq_options, nil
23
+ end
24
+ end
25
+
26
+ namespace :deploy do
27
+ before :starting, :check_sidekiq_hooks do
28
+ invoke 'sidekiq:add_default_hooks' if fetch(:sidekiq_default_hooks)
29
+ end
30
+ end
31
+
32
+ namespace :sidekiq do
33
+ task :add_default_hooks do
34
+ after 'deploy:starting', 'sidekiq:quiet'
35
+ after 'deploy:updated', 'sidekiq:stop'
36
+ after 'deploy:published', 'sidekiq:start'
37
+ after 'deploy:failed', 'sidekiq:restart'
38
+ end
39
+
40
+ desc 'Quiet sidekiq (stop fetching new tasks from Redis)'
41
+ task :quiet do
42
+ on roles fetch(:sidekiq_roles) do |role|
43
+ switch_user(role) do
44
+ sidekiq_options_per_process.each_index do |index|
45
+ execute :systemctl, "--user", "reload", service_unit_name(index), raise_on_non_zero_exit: false
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ desc 'Stop sidekiq (graceful shutdown within timeout, put unfinished tasks back to Redis)'
52
+ task :stop do
53
+ on roles fetch(:sidekiq_roles) do |role|
54
+ switch_user(role) do
55
+ sidekiq_options_per_process.each_index do |index|
56
+ execute :systemctl, "--user", "stop", service_unit_name(index)
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ desc 'Start sidekiq'
63
+ task :start do
64
+ on roles fetch(:sidekiq_roles) do |role|
65
+ switch_user(role) do
66
+ sidekiq_options_per_process.each_index do |index|
67
+ execute :systemctl, "--user", "start", service_unit_name(index)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ desc 'Restart sidekiq'
74
+ task :restart do
75
+ invoke! 'sidekiq:stop'
76
+ invoke! 'sidekiq:start'
77
+ end
78
+
79
+ desc 'Generate and upload .service files'
80
+ task :install do
81
+ on roles fetch(:sidekiq_roles) do |role|
82
+ switch_user(role) do
83
+ create_systemd_template(role)
84
+ sidekiq_options_per_process.each_index do |index|
85
+ execute :systemctl, "--user", "enable", service_unit_name(index)
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ desc 'Uninstall .service files'
92
+ task :uninstall do
93
+ on roles fetch(:sidekiq_roles) do |role|
94
+ switch_user(role) do
95
+ sidekiq_options_per_process.each_index do |index|
96
+ execute :systemctl, "--user", "disable", service_unit_name(index)
97
+ execute :rm, File.join(fetch(:service_unit_path, File.join(capture(:pwd), ".config", "systemd", "user")),service_unit_name(index))
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def create_systemd_template(role)
104
+ template = File.read(File.expand_path('../../../../generators/capistrano/sidekiq/systemd/templates/sidekiq.service.capistrano.erb', __FILE__))
105
+ home_dir = capture :pwd
106
+ systemd_path = fetch(:service_unit_path, File.join(home_dir, ".config", "systemd", "user"))
107
+ sidekiq_cmd = SSHKit.config.command_map[:sidekiq].gsub('~', home_dir)
108
+ execute :mkdir, "-p", systemd_path
109
+ sidekiq_options_per_process.each_index do |index|
110
+ upload!(StringIO.new(ERB.new(template).result(binding)), "#{systemd_path}/#{service_unit_name(index)}")
111
+ end
112
+ execute :systemctl, "--user", "daemon-reload"
113
+ end
114
+
115
+ def process_options(index = 0)
116
+ args = []
117
+ args.push "--environment #{fetch(:sidekiq_env)}"
118
+ %w{require queue config concurrency}.each do |option|
119
+ options = fetch(:sidekiq_options_per_process)&.[](index)
120
+ Array((options.is_a?(Hash) && options[option.to_sym]) || fetch(:"sidekiq_#{option}")).each do |value|
121
+ args.push "--#{option} #{value}"
122
+ end
123
+ end
124
+ if (process_options = fetch(:sidekiq_options_per_process)&.[](index)).is_a?(String)
125
+ args.push process_options
126
+ end
127
+
128
+ args.push "--tag #{service_unit_name(index)}" # Used to be able to identify service by monit via regex
129
+
130
+ # use sidekiq_options for special options
131
+ options = fetch(:sidekiq_options_per_process)&.[](index)
132
+ Array((options.is_a?(Hash) && options[:sidekiq_options]) || fetch(:sidekiq_options)).each do |value|
133
+ args.push value
134
+ end
135
+ args.compact.join(' ')
136
+ end
137
+
138
+ def switch_user(role)
139
+ su_user = sidekiq_user(role)
140
+ if su_user == role.user
141
+ yield
142
+ else
143
+ as su_user do
144
+ yield
145
+ end
146
+ end
147
+ end
148
+
149
+ def sidekiq_user(role)
150
+ properties = role.properties
151
+ properties.fetch(:sidekiq_user) || # local property for sidekiq only
152
+ fetch(:sidekiq_user) ||
153
+ properties.fetch(:run_as) || # global property across multiple capistrano gems
154
+ role.user
155
+ end
156
+
157
+ def sidekiq_options_per_process
158
+ fetch(:sidekiq_options_per_process) || [nil]
159
+ end
160
+
161
+ def service_unit_name(index)
162
+ if multiple_processes?
163
+ options = fetch(:sidekiq_options_per_process)&.[](index)
164
+ (options.is_a?(Hash) && options[:service_unit_name]) || fetch(:service_unit_name).gsub(/(.*)\.service/, "\\1-#{index}.service")
165
+ else
166
+ fetch(:service_unit_name)
167
+ end
168
+ end
169
+
170
+ def max_mem(index, service = :systemd)
171
+ if multiple_processes?
172
+ options = fetch(:sidekiq_options_per_process)&.[](index)
173
+ case service
174
+ when :systemd
175
+ (options.is_a?(Hash) && options[:sidekiq_max_mem]) || fetch(:sidekiq_max_mem)
176
+ when :monit
177
+ (options.is_a?(Hash) && options[:sidekiq_monit_max_mem]) || fetch(:sidekiq_monit_max_mem)
178
+ end
179
+ elsif service == :systemd
180
+ fetch(:sidekiq_max_mem)
181
+ elsif service == :monit
182
+ fetch(:sidekiq_monit_max_mem)
183
+ end
184
+ end
185
+
186
+ def multiple_processes?
187
+ fetch(:sidekiq_options_per_process) && fetch(:sidekiq_options_per_process).size > 1
188
+ end
189
+ end
@@ -0,0 +1,8 @@
1
+ # Monit configuration for Sidekiq : <%= fetch(:application) %>
2
+ <% sidekiq_options_per_process.each_index do |index| %>
3
+ check process <%= service_unit_name(index) %> matching "<%= service_unit_name(index) %>"
4
+ start program = "/bin/systemctl start <%= service_unit_name(index) %>"
5
+ stop program = "/bin/systemctl stop <%= service_unit_name(index) %>"
6
+ group <%= fetch(:sidekiq_monit_group) || fetch(:application) %>-sidekiq
7
+ <%= "if totalmem is greater than #{max_mem(index, :monit)} MB for 2 cycles then restart" if max_mem(index, :monit) %>
8
+ <% end %>
@@ -0,0 +1,25 @@
1
+ [Unit]
2
+ Description=sidekiq for <%= "#{fetch(:application)} (#{fetch(:stage)})" %>
3
+ After=syslog.target network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ Environment=RAILS_ENV=<%= fetch(:rails_env) %>
8
+ WorkingDirectory=<%= fetch(:deploy_to) %>/current
9
+ ExecStart=<%= sidekiq_cmd %> <%= process_options(index) %>
10
+ ExecReload=/bin/kill -TSTP $MAINPID
11
+ ExecStop=/bin/kill -TERM $MAINPID
12
+ <%= "MemoryAccounting=#{ !!max_mem(index) }" if max_mem(index) %>
13
+ <%= "MemoryLimit=#{ max_mem(index) }" if max_mem(index) %>
14
+
15
+ # Greatly reduce Ruby memory fragmentation and heap usage
16
+ # https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/
17
+ Environment=MALLOC_ARENA_MAX=2
18
+
19
+ RestartSec=1
20
+ Restart=on-failure
21
+
22
+ SyslogIdentifier=sidekiq
23
+
24
+ [Install]
25
+ WantedBy=default.target
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-sidekiq-systemd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - spilin
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capistrano
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.9.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.9.0
27
+ description: Capistrano sidekiq systemd support. Allows to deploy multiple processes.
28
+ email:
29
+ - lyoshakr@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - ".rspec"
36
+ - ".travis.yml"
37
+ - CHANGELOG.md
38
+ - CODE_OF_CONDUCT.md
39
+ - Gemfile
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - bin/console
44
+ - bin/setup
45
+ - capistrano-sidekiq-systemd.gemspec
46
+ - lib/capistrano/sidekiq/monit.rb
47
+ - lib/capistrano/sidekiq/systemd.rb
48
+ - lib/capistrano/sidekiq/systemd/version.rb
49
+ - lib/capistrano/sidekiq/tasks/monit.rake
50
+ - lib/capistrano/sidekiq/tasks/systemd.rake
51
+ - lib/generators/capistrano/sidekiq/monit/templates/sidekiq.conf.capistrano.erb
52
+ - lib/generators/capistrano/sidekiq/systemd/templates/sidekiq.service.capistrano.erb
53
+ homepage: https://github.com/spilin/capistrano-sidekiq-systemd
54
+ licenses:
55
+ - MIT
56
+ metadata:
57
+ homepage_uri: https://github.com/spilin/capistrano-sidekiq-systemd
58
+ source_code_uri: https://github.com/spilin/capistrano-sidekiq-systemd
59
+ changelog_uri: https://github.com/spilin/capistrano-sidekiq-systemd/CHANGELOG.md
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.0.6
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Capistrano sidekiq systemd support
79
+ test_files: []