├── lib ├── capistrano-sidekiq.rb └── capistrano │ ├── sidekiq │ ├── version.rb │ └── systemd.rb │ ├── tasks │ ├── sidekiq.rake │ ├── helpers.rake │ └── systemd.rake │ ├── templates │ └── sidekiq.service.capistrano.erb │ └── sidekiq.rb ├── .tool-versions ├── test ├── app │ ├── Gemfile │ ├── config │ │ └── sidekiq.yml │ └── config.ru ├── config │ ├── deploy │ │ └── production.rb │ └── deploy.rb ├── Capfile ├── Dockerfile ├── test_helper.rb ├── unit_test.rb └── deploy_test.rb ├── LICENSE.txt ├── Gemfile ├── .gitignore ├── .github └── workflows │ ├── stale.yml │ └── test.yml ├── Rakefile ├── capistrano-sidekiq.gemspec ├── .rubocop.yml ├── coss.toml ├── CONTRIBUTING.md ├── MIGRATION_FROM_V2.md ├── SYSTEMD.md ├── docs └── SYSTEMD_INTEGRATION.md ├── README.md └── CHANGELOG.md /lib/capistrano-sidekiq.rb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 3.4.4 2 | -------------------------------------------------------------------------------- /test/app/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'sidekiq', '~> 7.3' 4 | gem 'redis', '~> 5.0' 5 | gem 'sinatra' -------------------------------------------------------------------------------- /lib/capistrano/sidekiq/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Capistrano 4 | SIDEKIQ_VERSION = '3.2.0' 5 | end 6 | -------------------------------------------------------------------------------- /test/app/config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | :verbose: true 2 | :pidfile: ./tmp/pids/sidekiq.pid 3 | :logfile: ./log/sidekiq.log 4 | :concurrency: 2 5 | :queues: 6 | - default 7 | - critical -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Abdelkader Boudih 2 | 3 | capistrano-sidekiq is an Open Source project licensed under the terms of 4 | the LGPLv3 license. Please see 5 | for license text. 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | # Specify your gem's dependencies in capistrano-sidekiq.gemspec 6 | gemspec 7 | 8 | # Ruby 3.4+ compatibility 9 | gem 'base64' 10 | gem 'mutex_m' 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | .idea 19 | *.iml -------------------------------------------------------------------------------- /test/config/deploy/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | server 'localhost', user: 'deploy', roles: %w[app web worker], port: 8022, 4 | ssh_options: { 5 | password: 'password', 6 | auth_methods: %w[password], 7 | user_known_hosts_file: '/dev/null' 8 | } 9 | -------------------------------------------------------------------------------- /test/Capfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'capistrano/setup' 4 | require 'capistrano/deploy' 5 | require 'capistrano/bundler' 6 | require 'capistrano/rails/assets' 7 | require 'capistrano/rails/migrations' 8 | require 'capistrano/scm/git' 9 | install_plugin Capistrano::SCM::Git 10 | 11 | require_relative '../lib/capistrano/sidekiq' 12 | install_plugin Capistrano::Sidekiq 13 | install_plugin Capistrano::Sidekiq::Systemd 14 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "30 1 * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/stale@v3 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | stale-issue-message: 'Stale issue message' 17 | stale-pr-message: 'Stale pull request message' 18 | stale-issue-label: 'no-issue-activity' 19 | stale-pr-label: 'no-pr-activity' -------------------------------------------------------------------------------- /test/app/config.ru: -------------------------------------------------------------------------------- 1 | require 'sinatra' 2 | require 'sidekiq' 3 | require 'sidekiq/web' 4 | 5 | # Simple worker for testing 6 | class TestWorker 7 | include Sidekiq::Worker 8 | 9 | def perform(name = "test") 10 | puts "Processing job for #{name}" 11 | end 12 | end 13 | 14 | get '/' do 15 | 'Hello, Sidekiq' 16 | end 17 | 18 | get '/test' do 19 | TestWorker.perform_async('capistrano-sidekiq-test') 20 | 'Job enqueued' 21 | end 22 | 23 | run Rack::URLMap.new('/' => Sinatra::Application, '/sidekiq' => Sidekiq::Web) -------------------------------------------------------------------------------- /test/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:3.4 2 | 3 | RUN apt-get update && apt-get install -y systemd systemd-sysv openssh-server sudo redis-server && \ 4 | apt-get clean && \ 5 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 6 | 7 | RUN groupadd --system --gid 1000 deploy && \ 8 | useradd deploy --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ 9 | chown -R deploy:deploy /var 10 | RUN echo "deploy ALL=(ALL) NOPASSWD:ALL" | tee /etc/sudoers.d/deploy 11 | RUN echo 'deploy:password' | chpasswd 12 | 13 | # Enable systemd lingering for deploy user 14 | RUN mkdir -p /var/lib/systemd/linger && touch /var/lib/systemd/linger/deploy 15 | 16 | EXPOSE 22 17 | CMD ["/lib/systemd/systemd"] -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/gem_tasks' 4 | require 'rake/testtask' 5 | 6 | Rake::TestTask.new(:test) do |t| 7 | t.libs << 'test' 8 | t.libs << 'lib' 9 | 10 | # Run unit tests in CI, all tests locally 11 | t.pattern = if ENV['CI'] 12 | 'test/unit_test.rb' 13 | else 14 | 'test/**/*_test.rb' 15 | end 16 | 17 | t.verbose = true 18 | end 19 | 20 | Rake::TestTask.new(:unit) do |t| 21 | t.libs << 'test' 22 | t.libs << 'lib' 23 | t.pattern = 'test/unit_test.rb' 24 | t.verbose = true 25 | end 26 | 27 | Rake::TestTask.new(:integration) do |t| 28 | t.libs << 'test' 29 | t.libs << 'lib' 30 | t.pattern = 'test/deploy_test.rb' 31 | t.verbose = true 32 | end 33 | 34 | task default: :test 35 | -------------------------------------------------------------------------------- /test/config/deploy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lock '~> 3.17.0' 4 | 5 | set :application, 'capistrano_sidekiq_test' 6 | set :repo_url, 'https://github.com/seuros/capistrano-sidekiq.git' 7 | set :branch, 'master' 8 | set :deploy_to, '/var/www/capistrano_sidekiq_test' 9 | set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system') 10 | 11 | # Sidekiq configuration 12 | set :sidekiq_roles, :worker 13 | set :sidekiq_config, 'config/sidekiq.yml' 14 | set :sidekiq_service_unit_user, :user 15 | 16 | namespace :deploy do 17 | after :restart, :clear_cache do 18 | on roles(:web), in: :groups, limit: 3, wait: 10 do 19 | # Here we can do anything such as: 20 | # within release_path do 21 | # execute :rake, 'cache:clear' 22 | # end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | rake: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | ruby-version: ['3.2', '3.3', '3.4'] 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | 20 | - name: Set up Ruby 21 | uses: ruby/setup-ruby@v1 22 | with: 23 | ruby-version: ${{ matrix.ruby-version }} 24 | bundler-cache: true 25 | 26 | - name: Run RuboCop 27 | run: bundle exec rubocop 28 | 29 | - name: Run Tests 30 | run: bundle exec rake test 31 | 32 | - name: Upload test results 33 | if: always() 34 | uses: actions/upload-artifact@v4 35 | with: 36 | name: test-results-${{ matrix.ruby-version }} 37 | path: | 38 | test/log/*.log 39 | test/*.log 40 | -------------------------------------------------------------------------------- /capistrano-sidekiq.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/capistrano/sidekiq/version' 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'capistrano-sidekiq' 7 | spec.version = Capistrano::SIDEKIQ_VERSION 8 | spec.authors = ['Abdelkader Boudih'] 9 | spec.email = ['terminale@gmail.com'] 10 | spec.description = 'Sidekiq integration for Capistrano' 11 | spec.summary = 'Sidekiq integration for Capistrano' 12 | spec.homepage = 'https://github.com/seuros/capistrano-sidekiq' 13 | spec.license = 'LGPL-3.0' 14 | 15 | spec.required_ruby_version = '>= 3.2.0' 16 | 17 | spec.files = Dir.glob('lib/**/*') + %w[README.md CHANGELOG.md LICENSE.txt] 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_dependency 'capistrano', '>= 3.9.0' 21 | spec.add_dependency 'capistrano-bundler' 22 | spec.add_dependency 'sidekiq', '>= 7.0' 23 | 24 | spec.add_development_dependency 'minitest', '~> 5.0' 25 | spec.add_development_dependency 'rake', '~> 13.0' 26 | spec.add_development_dependency 'rubocop', '~> 1.50' 27 | spec.add_development_dependency 'rubocop-minitest', '~> 0.30' 28 | spec.add_development_dependency 'rubocop-rake', '~> 0.6' 29 | 30 | spec.post_install_message = ' 31 | Version 3.0.0 is a major release. Please see README.md, breaking changes are listed in CHANGELOG.md 32 | ' 33 | spec.metadata['rubygems_mfa_required'] = 'true' 34 | end 35 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/sidekiq.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :deploy do 4 | before :starting, :check_sidekiq_hooks do 5 | invoke 'sidekiq:add_default_hooks' if fetch(:sidekiq_default_hooks) 6 | end 7 | end 8 | 9 | namespace :sidekiq do 10 | task :add_default_hooks do 11 | after 'deploy:starting', 'sidekiq:quiet' if Rake::Task.task_defined?('sidekiq:quiet') 12 | after 'deploy:updated', 'sidekiq:stop' 13 | after 'deploy:reverted', 'sidekiq:stop' 14 | after 'deploy:published', 'sidekiq:start' 15 | after 'deploy:published', 'sidekiq:mark_deploy' if fetch(:sidekiq_mark_deploy, false) 16 | after 'deploy:failed', 'sidekiq:restart' 17 | end 18 | 19 | desc 'Mark deployment in Sidekiq metrics' 20 | task :mark_deploy do 21 | if fetch(:sidekiq_mark_deploy, false) 22 | on roles(fetch(:sidekiq_roles)) do 23 | within current_path do 24 | # Get deploy label - use custom label or git description 25 | deploy_label = fetch(:sidekiq_deploy_label) || begin 26 | capture(:git, 'log', '-1', '--format="%h %s"').strip 27 | rescue StandardError 28 | "#{fetch(:application)} #{fetch(:stage)} deploy" 29 | end 30 | 31 | info "Marking deployment in Sidekiq metrics: #{deploy_label}" 32 | 33 | # Create a Ruby script to mark the deployment 34 | mark_deploy_script = <<~RUBY 35 | require 'sidekiq/deploy' 36 | Sidekiq::Deploy.mark!(ARGV[0]) 37 | RUBY 38 | 39 | # Execute the script with the deploy label 40 | execute :bundle, :exec, :ruby, '-e', mark_deploy_script, '--', deploy_label 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/setup' 4 | require 'minitest/autorun' 5 | 6 | # Set up test environment 7 | ENV['TEST'] = 'true' 8 | 9 | # Set up minimal Capistrano environment for testing 10 | require 'capistrano/plugin' 11 | 12 | # Set up a minimal Capistrano environment for testing 13 | module Capistrano 14 | class Plugin 15 | def set_defaults; end 16 | def define_tasks; end 17 | def register_hooks; end 18 | end 19 | 20 | module DSL 21 | module Env 22 | def fetch(key, default = nil, &block) 23 | @config ||= {} 24 | @config[key] || (block_given? ? block.call : default) 25 | end 26 | 27 | def set(key, value) 28 | @config ||= {} 29 | @config[key] = value 30 | end 31 | 32 | def set_if_empty(key, value) 33 | @config ||= {} 34 | @config[key] ||= value.respond_to?(:call) ? value : value 35 | end 36 | 37 | def append(key, *values) 38 | @config ||= {} 39 | @config[key] ||= [] 40 | @config[key].concat(values) 41 | end 42 | end 43 | end 44 | 45 | class Configuration 46 | include DSL::Env 47 | end 48 | 49 | def self.configuration 50 | @configuration ||= Configuration.new 51 | end 52 | 53 | class Plugin 54 | include DSL::Env 55 | 56 | def self.config 57 | Capistrano.configuration 58 | end 59 | 60 | def fetch(*, &) 61 | self.class.config.fetch(*, &) 62 | end 63 | 64 | def set(*) 65 | self.class.config.set(*) 66 | end 67 | 68 | def set_if_empty(*) 69 | self.class.config.set_if_empty(*) 70 | end 71 | 72 | def append(*) 73 | self.class.config.append(*) 74 | end 75 | end 76 | end 77 | 78 | # Load the gem without bundler dependency 79 | require 'capistrano/sidekiq' 80 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - rubocop-minitest 3 | - rubocop-rake 4 | 5 | AllCops: 6 | TargetRubyVersion: 3.2 7 | NewCops: enable 8 | Exclude: 9 | - 'vendor/**/*' 10 | - 'pkg/**/*' 11 | - 'test/app/**/*' 12 | - 'tmp/**/*' 13 | 14 | # Layout cops 15 | Layout/LineLength: 16 | Max: 120 17 | Exclude: 18 | - 'test/**/*' 19 | 20 | # Style cops 21 | Style/Documentation: 22 | Enabled: false 23 | 24 | Style/FrozenStringLiteralComment: 25 | Enabled: true 26 | EnforcedStyle: always 27 | 28 | Style/StringLiterals: 29 | EnforcedStyle: single_quotes 30 | 31 | Style/HashSyntax: 32 | EnforcedStyle: ruby19 33 | 34 | Style/IdenticalConditionalBranches: 35 | Exclude: 36 | - 'test/**/*' 37 | 38 | # Metrics cops 39 | Metrics/MethodLength: 40 | Max: 20 41 | Exclude: 42 | - 'test/**/*' 43 | 44 | Metrics/ClassLength: 45 | Max: 200 46 | Exclude: 47 | - 'test/**/*' 48 | 49 | Metrics/BlockLength: 50 | Exclude: 51 | - 'test/**/*' 52 | - '*.gemspec' 53 | - 'Rakefile' 54 | - 'lib/capistrano/tasks/**/*' 55 | 56 | Metrics/AbcSize: 57 | Exclude: 58 | - 'test/**/*' 59 | - 'lib/capistrano/tasks/**/*' 60 | - 'lib/capistrano/sidekiq.rb' 61 | - 'lib/capistrano/sidekiq/systemd.rb' 62 | 63 | Minitest/MultipleAssertions: 64 | Max: 15 65 | 66 | # Minitest cops 67 | Minitest/AssertEmptyLiteral: 68 | Enabled: true 69 | 70 | Minitest/AssertTruthy: 71 | Enabled: true 72 | 73 | Minitest/RefuteFalse: 74 | Enabled: true 75 | 76 | # Rake cops 77 | Rake/Desc: 78 | Enabled: false 79 | 80 | Rake/MethodDefinitionInTask: 81 | Enabled: false 82 | 83 | # Naming cops 84 | Naming/FileName: 85 | Exclude: 86 | - 'lib/capistrano-sidekiq.rb' 87 | 88 | # Gemspec cops 89 | Gemspec/DevelopmentDependencies: 90 | Enabled: false 91 | 92 | # Lint cops 93 | Lint/MissingSuper: 94 | Exclude: 95 | - 'lib/capistrano/**/*' 96 | 97 | Lint/EmptyFile: 98 | Exclude: 99 | - 'lib/capistrano-sidekiq.rb' 100 | 101 | Lint/DuplicateBranch: 102 | Exclude: 103 | - 'test/**/*' -------------------------------------------------------------------------------- /test/unit_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'test_helper' 4 | 5 | class UnitTest < Minitest::Test 6 | def setup 7 | @plugin = Capistrano::Sidekiq.new 8 | end 9 | 10 | def test_plugin_defines_tasks 11 | # Verify the plugin can be instantiated 12 | assert_instance_of Capistrano::Sidekiq, @plugin 13 | end 14 | 15 | def test_sidekiq_common_module 16 | obj = Object.new 17 | obj.extend(Capistrano::SidekiqCommon) 18 | 19 | # Test sidekiq_config method 20 | obj.instance_variable_set(:@config_file, 'custom.yml') 21 | 22 | assert_equal '--config config/custom.yml', obj.sidekiq_config 23 | 24 | obj.instance_variable_set(:@config_file, 'sidekiq.yml') 25 | 26 | assert_nil obj.sidekiq_config 27 | end 28 | 29 | def test_systemd_plugin 30 | systemd = Capistrano::Sidekiq::Systemd.new 31 | 32 | assert_instance_of Capistrano::Sidekiq::Systemd, systemd 33 | end 34 | 35 | def test_version_constant 36 | assert_match(/^\d+\.\d+\.\d+/, Capistrano::SIDEKIQ_VERSION) 37 | end 38 | end 39 | 40 | class SidekiqCommonTest < Minitest::Test 41 | include Capistrano::SidekiqCommon 42 | 43 | def fetch(key, default = nil) 44 | @config ||= {} 45 | @config[key] || default 46 | end 47 | 48 | def test_sidekiq_user_with_nil_role 49 | @config = { sidekiq_user: 'sidekiq' } 50 | 51 | assert_equal 'sidekiq', sidekiq_user(nil) 52 | end 53 | 54 | def test_sidekiq_user_with_role 55 | role = Struct.new(:user, :properties).new('deploy', {}) 56 | @config = {} 57 | 58 | assert_equal 'deploy', sidekiq_user(role) 59 | end 60 | 61 | def test_sidekiq_user_with_role_property 62 | role = Struct.new(:user, :properties).new('deploy', { sidekiq_user: 'custom' }) 63 | @config = {} 64 | 65 | assert_equal 'custom', sidekiq_user(role) 66 | end 67 | 68 | def test_sidekiq_config_default 69 | @config_file = 'sidekiq.yml' 70 | 71 | assert_nil sidekiq_config 72 | end 73 | 74 | def test_sidekiq_config_custom 75 | @config_file = 'custom.yml' 76 | 77 | assert_equal '--config config/custom.yml', sidekiq_config 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/capistrano/templates/sidekiq.service.capistrano.erb: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/mperham/sidekiq/blob/master/examples/systemd/sidekiq.service 2 | # 3 | # This file tells systemd how to run Sidekiq as a 24/7 long-running daemon. 4 | 5 | # Then run: 6 | # - systemctl enable <%= sidekiq_service_unit_name(@config_file) %> 7 | # - systemctl {start,stop,restart} <%= sidekiq_service_unit_name(@config_file) %> 8 | # 9 | # Use `journalctl -u <%= sidekiq_service_unit_name(@config_file) %> -rn 100` to view the last 100 lines of log output. 10 | # 11 | [Unit] 12 | Description=Sidekiq for <%= "#{fetch(:application)} (#{fetch(:stage)})" %> 13 | # start us only once the network and logging subsystems are available, 14 | # consider adding redis-server.service if Redis is local and systemd-managed. 15 | After=syslog.target network.target 16 | 17 | [Service] 18 | Type=notify 19 | # If your Sidekiq process locks up, systemd's watchdog will restart it within seconds. 20 | WatchdogSec=10 21 | <%="User=#{sidekiq_user}" if fetch(:sidekiq_systemctl_user) == :system %> 22 | WorkingDirectory=<%= current_path %> 23 | <% if fetch(:sidekiq_use_login_shell) %> 24 | ExecStart=/bin/bash -lc '<%= expanded_bundle_command %> exec <%= fetch(:sidekiq_command) %> <%= fetch(:sidekiq_command_args) %> <%= sidekiq_config %>' 25 | <% else %> 26 | ExecStart=<%= expanded_bundle_command %> exec <%= fetch(:sidekiq_command) %> <%= fetch(:sidekiq_command_args) %> <%= sidekiq_config %> 27 | <% end %> 28 | 29 | # Use `systemctl kill -s TSTP <% sidekiq_service_unit_name(@config_file) %>` to quiet the Sidekiq process 30 | UMask=0002 31 | 32 | <%- Array(fetch(:sidekiq_service_unit_env_files)).each do |file| %> 33 | <%="EnvironmentFile=#{file}" %> 34 | <% end -%> 35 | <% Array(fetch(:sidekiq_service_unit_env_vars)).each do |environment_variable| %> 36 | <%="Environment=\"#{environment_variable}\"" %> 37 | <% end -%> 38 | 39 | # if we crash, restart 40 | RestartSec=1 41 | Restart=on-failure 42 | 43 | <%="StandardOutput=append:#{fetch(:sidekiq_log)}" if fetch(:sidekiq_log) -%> 44 | 45 | <%="StandardError=append:#{fetch(:sidekiq_error_log)}" if fetch(:sidekiq_error_log) -%> 46 | 47 | SyslogIdentifier=<%= sidekiq_service_unit_name(@config_file) %> 48 | [Install] 49 | WantedBy=<%=(fetch(:sidekiq_systemctl_user) == :system) ? "multi-user.target" : "default.target"%> 50 | -------------------------------------------------------------------------------- /coss.toml: -------------------------------------------------------------------------------- 1 | # COSS (Contribution Open Source Specification) v0.0.2 2 | # This file provides standardized metadata for the capistrano-sidekiq project 3 | 4 | [project] 5 | name = "capistrano-sidekiq" 6 | version = "3.0.0" 7 | description = "Sidekiq integration for Capistrano - manage Sidekiq processes during deployments" 8 | licenses = ["LGPL-3.0"] 9 | homepage = "https://github.com/seuros/capistrano-sidekiq" 10 | 11 | [repository] 12 | url = "https://github.com/seuros/capistrano-sidekiq" 13 | type = "git" 14 | default_branch = "master" 15 | 16 | [issues] 17 | url = "https://github.com/seuros/capistrano-sidekiq/issues" 18 | type = "github" 19 | 20 | [technical] 21 | primary_languages = ["Ruby"] 22 | frameworks = ["Capistrano", "Sidekiq"] 23 | minimum_ruby_version = "3.2.0" 24 | 25 | [build] 26 | commands = ["bundle install"] 27 | test_commands = ["bundle exec rake test"] 28 | 29 | [dependencies] 30 | runtime = [ 31 | "capistrano >= 3.9.0", 32 | "capistrano-bundler", 33 | "sidekiq >= 6.0.6" 34 | ] 35 | development = [ 36 | "minitest ~> 5.0", 37 | "rake ~> 13.0" 38 | ] 39 | 40 | [maintainers] 41 | [[maintainers.primary]] 42 | name = "Abdelkader Boudih" 43 | email = "terminale@gmail.com" 44 | github = "seuros" 45 | 46 | [maintenance] 47 | status = "active" 48 | release_process = """ 49 | 1. Update version in lib/capistrano/sidekiq/version.rb 50 | 2. Update CHANGELOG.md 51 | 3. Run tests: bundle exec rake test 52 | 4. Build gem: bundle exec rake build 53 | 5. Release: bundle exec rake release 54 | """ 55 | 56 | [quality] 57 | linting = "rubocop (planned)" 58 | testing_framework = "minitest" 59 | ci_platform = "GitHub Actions" 60 | code_coverage = "planned" 61 | 62 | [documentation] 63 | primary_docs = "README.md" 64 | additional_docs = [ 65 | "docs/SYSTEMD_INTEGRATION.md", 66 | "SYSTEMD.md", 67 | "CHANGELOG.md" 68 | ] 69 | api_docs = "YARD (planned)" 70 | 71 | [community] 72 | contributing_guide = "README.md#contributing" 73 | code_of_conduct = "planned" 74 | support_channels = [ 75 | "GitHub Issues", 76 | "GitHub Discussions (planned)" 77 | ] 78 | 79 | [security] 80 | security_policy = "planned" 81 | vulnerability_reporting = "via GitHub Security Advisories" 82 | 83 | [compatibility] 84 | sidekiq_versions = "7.0+" 85 | capistrano_versions = "3.9+" 86 | ruby_versions = "3.2+" 87 | systemd_versions = "206+" 88 | 89 | [features] 90 | systemd_integration = true 91 | multiple_processes = true 92 | per_server_configuration = true 93 | user_switching = true 94 | lingering_support = true 95 | custom_templates = true -------------------------------------------------------------------------------- /lib/capistrano/tasks/helpers.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :sidekiq do 4 | namespace :helpers do 5 | desc 'Generate multiple Sidekiq config files' 6 | task :generate_configs, :count do |_task, args| 7 | count = (args[:count] || 3).to_i 8 | 9 | puts "Generating #{count} Sidekiq config files..." 10 | 11 | # Base template 12 | base_config = { 13 | concurrency: 10, 14 | timeout: 25, 15 | verbose: false, 16 | strict: true 17 | } 18 | 19 | # Generate config files 20 | count.times do |i| 21 | config = base_config.dup 22 | 23 | # Assign queues based on index 24 | config[:queues] = case i 25 | when 0 26 | [['critical', 2], ['high', 1]] 27 | when 1 28 | [['default', 1], ['medium', 1]] 29 | else 30 | [['low', 1], ['background', 1]] 31 | end 32 | 33 | filename = i.zero? ? 'sidekiq.yml' : "sidekiq_#{i}.yml" 34 | filepath = "config/#{filename}" 35 | 36 | # Generate YAML content 37 | content = <<~YAML 38 | # Sidekiq configuration file #{i + 1}/#{count} 39 | :concurrency: #{config[:concurrency]} 40 | :timeout: #{config[:timeout]} 41 | :verbose: #{config[:verbose]} 42 | :strict: #{config[:strict]} 43 | 44 | :queues: 45 | YAML 46 | 47 | config[:queues].each do |queue, priority| 48 | content += " - [#{queue}, #{priority}]\n" 49 | end 50 | 51 | puts " Creating #{filepath}..." 52 | File.write(filepath, content) 53 | end 54 | 55 | puts "\nAdd to your deploy.rb:" 56 | puts "set :sidekiq_config_files, #{count.times.map do |i| 57 | i.zero? ? "'sidekiq.yml'" : "'sidekiq_#{i}.yml'" 58 | end.join(', ')}" 59 | end 60 | 61 | desc 'Show current Sidekiq configuration' 62 | task :show_config do 63 | on roles(fetch(:sidekiq_roles)) do 64 | within current_path do 65 | config_files = fetch(:sidekiq_config_files, ['sidekiq.yml']) 66 | 67 | config_files.each do |config_file| 68 | puts "\n=== #{config_file} ===" 69 | if test("[ -f config/#{config_file} ]") 70 | puts capture(:cat, "config/#{config_file}") 71 | else 72 | puts ' File not found' 73 | end 74 | end 75 | end 76 | end 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to capistrano-sidekiq 2 | 3 | We love pull requests from everyone. By participating in this project, you agree to abide by our code of conduct (coming soon). 4 | 5 | ## Getting Started 6 | 7 | 1. Fork the repository 8 | 2. Clone your fork: `git clone git@github.com:your-username/capistrano-sidekiq.git` 9 | 3. Set up your development environment: `bundle install` 10 | 4. Create a feature branch: `git checkout -b my-new-feature` 11 | 12 | ## Making Changes 13 | 14 | 1. Make your changes 15 | 2. Add tests for your changes 16 | 3. Run the test suite: `bundle exec rake test` 17 | 4. Update documentation if necessary 18 | 5. Update CHANGELOG.md with your changes 19 | 20 | ## Code Style 21 | 22 | - Follow Ruby community style guidelines 23 | - Keep code simple and readable 24 | - Add comments for complex logic 25 | - Use meaningful variable and method names 26 | 27 | ## Testing 28 | 29 | - Write tests for any new functionality 30 | - Ensure all tests pass before submitting 31 | - Test with different Ruby versions if possible 32 | - Test with Docker: `bundle exec rake test` 33 | 34 | ## Submitting Changes 35 | 36 | 1. Push to your fork: `git push origin my-new-feature` 37 | 2. Create a pull request 38 | 3. Describe your changes in the PR description 39 | 4. Reference any related issues 40 | 41 | ## Pull Request Guidelines 42 | 43 | - Keep PRs focused on a single feature or fix 44 | - Update documentation for any changed behavior 45 | - Add entries to CHANGELOG.md 46 | - Ensure CI passes 47 | - Be responsive to feedback 48 | 49 | ## Reporting Issues 50 | 51 | - Use the GitHub issue tracker 52 | - Check if the issue already exists 53 | - Include reproduction steps 54 | - Provide system information: 55 | - Ruby version 56 | - Capistrano version 57 | - Sidekiq version 58 | - Systemd version (if relevant) 59 | 60 | ## Development Setup 61 | 62 | ```bash 63 | # Clone the repo 64 | git clone https://github.com/seuros/capistrano-sidekiq.git 65 | cd capistrano-sidekiq 66 | 67 | # Install dependencies 68 | bundle install 69 | 70 | # Run tests 71 | bundle exec rake test 72 | 73 | # Run tests in Docker 74 | docker build -t capistrano-sidekiq-test test/ 75 | docker run capistrano-sidekiq-test 76 | ``` 77 | 78 | ## Release Process 79 | 80 | Releases are managed by maintainers. The process is: 81 | 82 | 1. Update version in `lib/capistrano/sidekiq/version.rb` 83 | 2. Update CHANGELOG.md 84 | 3. Run tests 85 | 4. Build gem: `bundle exec rake build` 86 | 5. Release: `bundle exec rake release` 87 | 88 | ## Questions? 89 | 90 | Feel free to open an issue for any questions about contributing. -------------------------------------------------------------------------------- /lib/capistrano/sidekiq/systemd.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Capistrano 4 | class Sidekiq 5 | class Systemd < Capistrano::Plugin 6 | include SidekiqCommon 7 | 8 | def define_tasks 9 | eval_rakefile File.expand_path('../tasks/systemd.rake', __dir__) 10 | eval_rakefile File.expand_path('../tasks/helpers.rake', __dir__) 11 | end 12 | 13 | def set_defaults 14 | set_if_empty :systemctl_bin, '/bin/systemctl' 15 | set_if_empty :service_unit_user, :user 16 | 17 | set_if_empty :sidekiq_systemctl_bin, -> { fetch(:systemctl_bin) } 18 | set_if_empty :sidekiq_service_unit_name, -> { "#{fetch(:application)}_sidekiq_#{fetch(:stage)}" } 19 | 20 | set_if_empty :sidekiq_systemctl_user, -> { fetch(:service_unit_user) } 21 | set_if_empty :sidekiq_enable_lingering, -> { fetch(:sidekiq_systemctl_user) != :system } 22 | set_if_empty :sidekiq_lingering_user, -> { fetch(:lingering_user, fetch(:user)) } 23 | 24 | ## Sidekiq could have a stripped down or more complex version of the environment variables 25 | set_if_empty :sidekiq_service_unit_env_files, -> { fetch(:service_unit_env_files, []) } 26 | set_if_empty :sidekiq_service_unit_env_vars, -> { fetch(:service_unit_env_vars, []) } 27 | 28 | set_if_empty :sidekiq_service_templates_path, fetch(:service_templates_path, 'config/deploy/templates') 29 | 30 | # Allow customization of the sidekiq command 31 | set_if_empty :sidekiq_command, 'sidekiq' 32 | set_if_empty :sidekiq_command_args, -> { "-e #{fetch(:sidekiq_env)}" } 33 | 34 | # Deployment tracking for Sidekiq 7+ metrics 35 | set_if_empty :sidekiq_mark_deploy, false 36 | set_if_empty :sidekiq_deploy_label, nil 37 | 38 | # Login shell option for loading environment 39 | set_if_empty :sidekiq_use_login_shell, false 40 | end 41 | 42 | def fetch_systemd_unit_path 43 | if fetch(:sidekiq_systemctl_user) == :system 44 | '/etc/systemd/system/' 45 | else 46 | home_dir = backend.capture :pwd 47 | File.join(home_dir, '.config', 'systemd', 'user') 48 | end 49 | end 50 | 51 | def systemd_command(*args) 52 | command = [fetch(:sidekiq_systemctl_bin)] 53 | 54 | command << '--user' unless fetch(:sidekiq_systemctl_user) == :system 55 | 56 | command + args 57 | end 58 | 59 | def sudo_if_needed(*command) 60 | if fetch(:sidekiq_systemctl_user) == :system 61 | backend.sudo command.map(&:to_s).join(' ') 62 | else 63 | backend.execute(*command) 64 | end 65 | end 66 | 67 | def execute_systemd(*) 68 | sudo_if_needed(*systemd_command(*)) 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /test/deploy_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'minitest/autorun' 4 | require 'net/http' 5 | require 'json' 6 | 7 | Minitest.after_run do 8 | DeployTest.container_id && system("docker stop #{DeployTest.container_id}") 9 | end 10 | 11 | class DeployTest < Minitest::Test 12 | class << self 13 | attr_accessor :container_id 14 | end 15 | 16 | def self.before_suite 17 | system 'docker build -t capistrano-sidekiq-test-server test' 18 | self.container_id = `docker run -d --privileged -p 8022:22 -p 3000:3000 -p 6379:6379 capistrano-sidekiq-test-server`.strip 19 | sleep 5 # Give systemd time to start 20 | 21 | # Start Redis inside container 22 | system "docker exec #{container_id} systemctl start redis-server" 23 | end 24 | 25 | before_suite 26 | 27 | def retry_get_response(uri, limit = 5) 28 | response = nil 29 | limit.times do 30 | response = Net::HTTP.get_response(URI.parse(uri)) 31 | rescue Errno::ECONNRESET, EOFError, Errno::ECONNREFUSED 32 | sleep 1 33 | else 34 | break 35 | end 36 | response 37 | end 38 | 39 | def test_deploy_and_sidekiq_operations 40 | Dir.chdir('test') do 41 | # Install systemd service 42 | assert system('cap production sidekiq:install'), 'Failed to install sidekiq service' 43 | 44 | # Deploy the application 45 | assert system('cap production deploy'), 'Failed to deploy application' 46 | 47 | # Check if web app is running 48 | response = retry_get_response('http://localhost:3000') 49 | 50 | assert_equal '200', response.code 51 | assert_equal 'Hello, Sidekiq', response.body 52 | 53 | # Test sidekiq:stop 54 | assert system('cap production sidekiq:stop'), 'Failed to stop sidekiq' 55 | sleep 2 56 | 57 | # Test sidekiq:start 58 | assert system('cap production sidekiq:start'), 'Failed to start sidekiq' 59 | sleep 2 60 | 61 | # Enqueue a test job 62 | response = retry_get_response('http://localhost:3000/test') 63 | 64 | assert_equal '200', response.code 65 | assert_equal 'Job enqueued', response.body 66 | 67 | # Test sidekiq:restart 68 | assert system('cap production sidekiq:restart'), 'Failed to restart sidekiq' 69 | sleep 2 70 | 71 | # Test sidekiq:quiet 72 | assert system('cap production sidekiq:quiet'), 'Failed to quiet sidekiq' 73 | 74 | # Check Sidekiq web UI 75 | response = retry_get_response('http://localhost:3000/sidekiq') 76 | 77 | assert_equal '200', response.code 78 | end 79 | end 80 | 81 | def test_multiple_processes 82 | skip 'Multiple process test - implement after fixing systemd issues' 83 | end 84 | 85 | def test_rollback_hooks 86 | skip 'Rollback hook test - implement after basic functionality works' 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/capistrano/sidekiq.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'capistrano/bundler' unless ENV['TEST'] 4 | require 'capistrano/plugin' 5 | 6 | module Capistrano 7 | module SidekiqCommon 8 | def compiled_template_sidekiq(from, role, config_file = 'sidekiq.yml') 9 | @role = role 10 | @config_file = config_file 11 | file = [ 12 | "lib/capistrano/templates/#{from}-#{role.hostname}-#{fetch(:stage)}.rb", 13 | "lib/capistrano/templates/#{from}-#{role.hostname}.rb", 14 | "lib/capistrano/templates/#{from}-#{fetch(:stage)}.rb", 15 | "lib/capistrano/templates/#{from}.rb.erb", 16 | "lib/capistrano/templates/#{from}.rb", 17 | "lib/capistrano/templates/#{from}.erb", 18 | "config/deploy/templates/#{from}.rb.erb", 19 | "config/deploy/templates/#{from}.rb", 20 | "config/deploy/templates/#{from}.erb", 21 | File.expand_path("../templates/#{from}.erb", __FILE__), 22 | File.expand_path("../templates/#{from}.rb.erb", __FILE__) 23 | ].detect { |path| File.file?(path) } 24 | erb = File.read(file) 25 | StringIO.new(ERB.new(erb, trim_mode: '-').result(binding)) 26 | end 27 | 28 | def template_sidekiq(from, to, role, config_file = 'sidekiq.yml') 29 | backend.upload! compiled_template_sidekiq(from, role, config_file), to 30 | end 31 | 32 | def expanded_bundle_command 33 | backend.capture(:echo, SSHKit.config.command_map[:bundle]).strip 34 | end 35 | 36 | def sidekiq_config 37 | "--config config/#{@config_file}" if @config_file != 'sidekiq.yml' 38 | end 39 | 40 | def sidekiq_switch_user(role, &) 41 | su_user = sidekiq_user(role) 42 | if su_user == role.user 43 | yield 44 | else 45 | backend.as(su_user, &) 46 | end 47 | end 48 | 49 | def sidekiq_user(role = nil) 50 | if role.nil? 51 | fetch(:sidekiq_user) 52 | else 53 | properties = role.properties 54 | return role.user unless properties 55 | 56 | properties.fetch(:sidekiq_user, nil) || # local property for sidekiq only 57 | fetch(:sidekiq_user, nil) || 58 | properties.fetch(:run_as, nil) || # global property across multiple capistrano gems 59 | role.user 60 | end 61 | end 62 | end 63 | 64 | class Sidekiq < Capistrano::Plugin 65 | def define_tasks 66 | eval_rakefile File.expand_path('tasks/sidekiq.rake', __dir__) 67 | end 68 | 69 | def set_defaults 70 | set_if_empty :sidekiq_default_hooks, true 71 | 72 | set_if_empty :sidekiq_env, -> { fetch(:rack_env, fetch(:rails_env, fetch(:rake_env, fetch(:stage)))) } 73 | set_if_empty :sidekiq_roles, fetch(:sidekiq_role, :worker) 74 | set_if_empty :sidekiq_configs, %w[sidekiq] # sidekiq.yml 75 | 76 | set_if_empty :sidekiq_log, -> { File.join(shared_path, 'log', 'sidekiq.log') } 77 | set_if_empty :sidekiq_error_log, -> { File.join(shared_path, 'log', 'sidekiq_error.log') } 78 | 79 | set_if_empty :sidekiq_config_files, ['sidekiq.yml'] 80 | 81 | # Rbenv, Chruby, and RVM integration 82 | append :rbenv_map_bins, 'sidekiq', 'sidekiqctl' 83 | append :rvm_map_bins, 'sidekiq', 'sidekiqctl' 84 | append :chruby_map_bins, 'sidekiq', 'sidekiqctl' 85 | # Bundler integration 86 | append :bundle_bins, 'sidekiq', 'sidekiqctl' 87 | end 88 | end 89 | end 90 | 91 | require_relative 'sidekiq/systemd' 92 | -------------------------------------------------------------------------------- /MIGRATION_FROM_V2.md: -------------------------------------------------------------------------------- 1 | # Migration Guide: From v2.x to v3.x 2 | 3 | This guide helps you migrate from capistrano-sidekiq v2.x to v3.x. 4 | 5 | ## Breaking Changes 6 | 7 | ### 1. Monit Support Removed 8 | 9 | **v3.0.0 removed monit support completely.** The gem now only supports systemd for service management. 10 | 11 | #### Before (v2.x with Monit): 12 | ```ruby 13 | # Capfile 14 | require 'capistrano/sidekiq' 15 | install_plugin Capistrano::Sidekiq 16 | install_plugin Capistrano::Sidekiq::Monit # No longer available 17 | ``` 18 | 19 | #### After (v3.x with Systemd only): 20 | ```ruby 21 | # Capfile 22 | require 'capistrano/sidekiq' 23 | install_plugin Capistrano::Sidekiq 24 | install_plugin Capistrano::Sidekiq::Systemd 25 | ``` 26 | 27 | ### 2. Default Role Changed 28 | 29 | The default role changed from `:app` to `:worker`. 30 | 31 | #### Before (v2.x): 32 | ```ruby 33 | # Sidekiq tasks ran on :app role by default 34 | server 'app1.example.com', roles: [:app] # Sidekiq would run here 35 | ``` 36 | 37 | #### After (v3.x): 38 | ```ruby 39 | # Sidekiq tasks now run on :worker role by default 40 | server 'worker1.example.com', roles: [:worker] # Sidekiq runs here 41 | 42 | # Or override the default: 43 | set :sidekiq_roles, :app # Use old behavior 44 | ``` 45 | 46 | ### 3. Task Names Changed 47 | 48 | Some task names have changed or been removed: 49 | 50 | - `sidekiq:monit:*` tasks are completely removed 51 | - Use standard systemd tasks: `sidekiq:start`, `sidekiq:stop`, `sidekiq:restart` 52 | 53 | ## Migration Steps 54 | 55 | ### Step 1: Update Your Gemfile 56 | 57 | ```ruby 58 | # Gemfile 59 | gem 'capistrano-sidekiq', '~> 3.0' 60 | ``` 61 | 62 | ### Step 2: Update Your Capfile 63 | 64 | ```ruby 65 | # Capfile 66 | require 'capistrano/sidekiq' 67 | install_plugin Capistrano::Sidekiq 68 | install_plugin Capistrano::Sidekiq::Systemd 69 | ``` 70 | 71 | ### Step 3: Update Your Deploy Configuration 72 | 73 | ```ruby 74 | # config/deploy.rb or config/deploy/production.rb 75 | 76 | # If you were using :app role, explicitly set it: 77 | set :sidekiq_roles, :app 78 | 79 | # Or update your server definitions to use :worker role: 80 | server 'worker1.example.com', roles: [:worker] 81 | ``` 82 | 83 | ### Step 4: Install Systemd Services 84 | 85 | Before your first deployment with v3.x: 86 | 87 | ```bash 88 | # Install systemd service files on your servers 89 | cap production sidekiq:install 90 | 91 | # This replaces any monit configuration you had 92 | ``` 93 | 94 | ### Step 5: Remove Monit Configuration 95 | 96 | On your servers, remove old monit configuration files: 97 | 98 | ```bash 99 | # On each server 100 | sudo rm /etc/monit/conf.d/sidekiq_* 101 | sudo monit reload 102 | ``` 103 | 104 | ## Troubleshooting 105 | 106 | ### "Don't know how to build task 'sidekiq:start'" 107 | 108 | Make sure you have both lines in your Capfile: 109 | ```ruby 110 | require 'capistrano/sidekiq' 111 | install_plugin Capistrano::Sidekiq::Systemd 112 | ``` 113 | 114 | ### "undefined method `as'" 115 | 116 | This is a known issue in v3.0.0. Make sure you're using the latest version which includes the fix. 117 | 118 | ### Sidekiq doesn't start after deployment 119 | 120 | 1. Check that systemd services are installed: 121 | ```bash 122 | cap production sidekiq:install 123 | ``` 124 | 125 | 2. Check service status: 126 | ```bash 127 | systemctl --user status sidekiq_myapp_production 128 | ``` 129 | 130 | 3. Ensure your servers have the `:worker` role or you've set `:sidekiq_roles` appropriately. 131 | 132 | ## Getting Help 133 | 134 | If you encounter issues during migration: 135 | 136 | 1. Check the [GitHub issues](https://github.com/seuros/capistrano-sidekiq/issues) 137 | 2. Review the [README](README.md) for current configuration options 138 | 3. Open a new issue with your specific migration problem -------------------------------------------------------------------------------- /SYSTEMD.md: -------------------------------------------------------------------------------- 1 | # Understanding Systemd Lingering in Capistrano Sidekiq 2 | 3 | ## What is Lingering? 4 | 5 | Lingering is a systemd feature that allows user services to run without an active user session. When lingering is enabled for a user: 6 | 7 | - Their user services can start at boot 8 | - Their user services continue running after they log out 9 | - Their user services can be managed independently of user sessions 10 | 11 | ## Why is Lingering Important for Sidekiq? 12 | 13 | When running Sidekiq as a user service (`:service_unit_user = :user`), lingering becomes important because: 14 | 15 | 1. Sidekiq needs to run continuously, even when no user is logged in 16 | 2. Sidekiq should start automatically after server reboots 17 | 3. Deployments should work regardless of active user sessions 18 | 19 | ## Configuration in Capistrano Sidekiq 20 | 21 | ```ruby 22 | set :sidekiq_lingering_user, -> { fetch(:lingering_user, fetch(:user)) } #lingering_user is optional, if the deploy user is the same 23 | set :service_unit_user, :user #set to :user to enable lingering 24 | ``` 25 | 26 | The plugin automatically enables lingering during the `sidekiq:enable` task when: 27 | - User-mode systemd is being used (`systemctl_user` is true) 28 | - A lingering user is specified 29 | 30 | ## How Lingering is Managed 31 | 32 | ### Enabling Lingering 33 | 34 | ```ruby 35 | # This happens automatically during sidekiq:enable if conditions are met 36 | execute :loginctl, "enable-linger", fetch(:sidekiq_lingering_user) 37 | ``` 38 | 39 | ### Checking Lingering Status 40 | 41 | You can manually check if lingering is enabled for a user: 42 | 43 | ```bash 44 | # Check lingering status 45 | loginctl show-user USERNAME | grep Linger 46 | 47 | # List all users with lingering enabled 48 | ls /var/lib/systemd/linger/ 49 | ``` 50 | 51 | ## Common Scenarios and Solutions 52 | 53 | ### Scenario 1: Running as Deploy User 54 | ```ruby 55 | # config/deploy.rb 56 | set :user, 'deploy' 57 | set :service_unit_user, :user 58 | # Lingering will be enabled for 'deploy' user 59 | ``` 60 | 61 | ### Scenario 2: Custom Lingering User 62 | ```ruby 63 | # config/deploy.rb 64 | set :user, 'deploy' 65 | set :lingering_user, 'sidekiq' 66 | set :service_unit_user, :user 67 | # Lingering will be enabled for 'sidekiq' user 68 | ``` 69 | 70 | ### Scenario 3: System Service (No Lingering Needed) 71 | ```ruby 72 | # config/deploy.rb 73 | set :service_unit_user, :system 74 | # Lingering is not relevant for system services 75 | ``` 76 | 77 | ## Troubleshooting 78 | 79 | 1. **Service Stops After Deployment** 80 | - Check if lingering is enabled: `loginctl show-user USERNAME | grep Linger` 81 | - Verify systemd user mode is correctly configured 82 | - Ensure the lingering user has appropriate permissions 83 | 84 | 2. **Service Doesn't Start on Boot** 85 | - Confirm lingering is enabled 86 | - Check systemd user service is enabled: `systemctl --user is-enabled sidekiq` 87 | - Verify service configuration in `~/.config/systemd/user/` 88 | 89 | 3. **Permission Issues** 90 | - Ensure the lingering user has access to required directories 91 | - Check if the user can write to log files and working directory 92 | - Verify systemd user instance is properly initialized 93 | 94 | ## Best Practices 95 | 96 | 1. **User Selection** 97 | - Use a dedicated service user for running Sidekiq 98 | - Ensure the user has minimal required permissions 99 | - Consider security implications of lingering enabled 100 | 101 | 2. **Configuration** 102 | - Always explicitly set `:service_unit_user` 103 | - Document lingering configuration in your deployment setup 104 | - Use consistent users across related services 105 | 106 | 3. **Monitoring** 107 | - Regularly check lingering status 108 | - Monitor service status after system reboots 109 | - Set up alerts for unexpected service stops 110 | 111 | ## System Requirements 112 | 113 | - Systemd version supporting user lingering (systemd >= 206) 114 | - Proper system permissions to enable lingering 115 | - Sufficient user permissions for service directories 116 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/systemd.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | git_plugin = self 4 | 5 | namespace :sidekiq do 6 | standard_actions = { 7 | start: 'Start Sidekiq', 8 | stop: 'Stop Sidekiq (graceful shutdown within timeout, put unfinished tasks back to Redis)', 9 | status: 'Get Sidekiq Status', 10 | restart: 'Restart Sidekiq' 11 | } 12 | standard_actions.each do |command, description| 13 | desc description 14 | task command do 15 | on roles fetch(:sidekiq_roles) do |role| 16 | git_plugin.sidekiq_switch_user(role) do 17 | git_plugin.config_files(role).each do |config_file| 18 | git_plugin.execute_systemd(command, git_plugin.sidekiq_service_file_name(config_file)) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | 25 | desc 'Quiet Sidekiq (stop fetching new tasks from Redis)' 26 | task :quiet do 27 | on roles fetch(:sidekiq_roles) do |role| 28 | git_plugin.sidekiq_switch_user(role) do 29 | git_plugin.quiet_sidekiq(role) 30 | end 31 | end 32 | end 33 | 34 | desc 'Install Sidekiq systemd service' 35 | task :install do 36 | on roles fetch(:sidekiq_roles) do |role| 37 | git_plugin.sidekiq_switch_user(role) do 38 | git_plugin.create_systemd_template(role) 39 | end 40 | end 41 | invoke 'sidekiq:enable' 42 | end 43 | 44 | desc 'Uninstall Sidekiq systemd service' 45 | task :uninstall do 46 | invoke 'sidekiq:disable' 47 | on roles fetch(:sidekiq_roles) do |role| 48 | git_plugin.sidekiq_switch_user(role) do 49 | git_plugin.rm_systemd_service(role) 50 | end 51 | end 52 | end 53 | 54 | desc 'Enable Sidekiq systemd service' 55 | task :enable do 56 | on roles(fetch(:sidekiq_roles)) do |role| 57 | git_plugin.config_files(role).each do |config_file| 58 | git_plugin.execute_systemd('enable', git_plugin.sidekiq_service_file_name(config_file)) 59 | end 60 | 61 | sudo :loginctl, 'enable-linger', fetch(:sidekiq_lingering_user) if fetch(:sidekiq_enable_lingering) 62 | end 63 | end 64 | 65 | desc 'Disable Sidekiq systemd service' 66 | task :disable do 67 | on roles(fetch(:sidekiq_roles)) do |role| 68 | git_plugin.config_files(role).each do |config_file| 69 | git_plugin.execute_systemd('disable', git_plugin.sidekiq_service_file_name(config_file)) 70 | end 71 | end 72 | end 73 | 74 | def fetch_systemd_unit_path 75 | if fetch(:sidekiq_systemctl_user) == :system 76 | '/etc/systemd/system/' 77 | else 78 | home_dir = backend.capture :pwd 79 | File.join(home_dir, '.config', 'systemd', 'user') 80 | end 81 | end 82 | 83 | def create_systemd_template(role) 84 | systemd_path = fetch(:service_unit_path, fetch_systemd_unit_path) 85 | backend.execute :mkdir, '-p', systemd_path if fetch(:sidekiq_systemctl_user) != :system 86 | 87 | config_files(role).each do |config_file| 88 | ctemplate = compiled_template_sidekiq('sidekiq.service.capistrano', role, config_file) 89 | temp_file_name = File.join('/tmp', "sidekiq.#{config_file}.service") 90 | systemd_file_name = File.join(systemd_path, sidekiq_service_file_name(config_file)) 91 | backend.upload!(ctemplate, temp_file_name) 92 | if fetch(:sidekiq_systemctl_user) == :system 93 | warn "Installing #{systemd_file_name} as root" 94 | backend.execute :sudo, :mv, temp_file_name, systemd_file_name 95 | else 96 | warn "Moving #{temp_file_name} to #{systemd_file_name}" 97 | backend.execute :mv, temp_file_name, systemd_file_name 98 | end 99 | end 100 | end 101 | 102 | def rm_systemd_service(role) 103 | systemd_path = fetch(:service_unit_path, fetch_systemd_unit_path) 104 | 105 | config_files(role).each do |config_file| 106 | systemd_file_name = File.join(systemd_path, sidekiq_service_file_name(config_file)) 107 | if fetch(:sidekiq_systemctl_user) == :system 108 | warn "Deleting #{systemd_file_name} as root" 109 | backend.execute :sudo, :rm, '-f', systemd_file_name 110 | else 111 | warn "Deleting #{systemd_file_name}" 112 | backend.execute :rm, '-f', systemd_file_name 113 | end 114 | end 115 | end 116 | 117 | def quiet_sidekiq(role) 118 | config_files(role).each do |config_file| 119 | sidekiq_service = sidekiq_service_unit_name(config_file) 120 | warn "Quieting #{sidekiq_service}" 121 | execute_systemd('kill -s TSTP', sidekiq_service) 122 | end 123 | end 124 | 125 | def sidekiq_service_unit_name(config_file) 126 | if config_file == 'sidekiq.yml' 127 | fetch(:sidekiq_service_unit_name) 128 | else 129 | "#{fetch(:sidekiq_service_unit_name)}.#{config_file.split('.')[0..-2].join('.')}" 130 | end 131 | end 132 | 133 | def sidekiq_service_file_name(config_file) 134 | ## Remove the extension 135 | config_file = config_file.split('.').join('.') 136 | 137 | "#{sidekiq_service_unit_name(config_file)}.service" 138 | end 139 | 140 | def config_files(role) 141 | role.properties.fetch(:sidekiq_config_files) || 142 | fetch(:sidekiq_config_files) 143 | end 144 | end 145 | -------------------------------------------------------------------------------- /docs/SYSTEMD_INTEGRATION.md: -------------------------------------------------------------------------------- 1 | # Systemd Integration Guide 2 | 3 | This document provides a comprehensive guide to using capistrano-sidekiq with systemd. 4 | 5 | ## Current State of Systemd Integration 6 | 7 | As of version 3.0.0, capistrano-sidekiq provides full systemd integration with the following features: 8 | 9 | - ✅ Automatic service file generation 10 | - ✅ Support for both system and user services 11 | - ✅ Multiple process management 12 | - ✅ Systemd lingering support 13 | - ✅ Log file management 14 | - ✅ Environment variable configuration 15 | - ✅ Per-server configuration 16 | 17 | ## Requirements 18 | 19 | - Systemd 240+ (for log file append support) 20 | - Systemd 206+ (for basic functionality) 21 | - Proper sudo permissions (for system services) 22 | 23 | ## Basic Setup 24 | 25 | ### 1. Add to Capfile 26 | 27 | ```ruby 28 | require 'capistrano/sidekiq' 29 | install_plugin Capistrano::Sidekiq 30 | install_plugin Capistrano::Sidekiq::Systemd 31 | ``` 32 | 33 | ### 2. Configure in deploy.rb 34 | 35 | ```ruby 36 | # Basic configuration 37 | set :sidekiq_roles, :worker 38 | set :sidekiq_config_files, ['sidekiq.yml'] 39 | 40 | # Choose service type 41 | set :service_unit_user, :user # or :system 42 | ``` 43 | 44 | ## Service Types 45 | 46 | ### User Services (Recommended) 47 | 48 | User services run under a specific user account without requiring root privileges. 49 | 50 | ```ruby 51 | set :service_unit_user, :user 52 | ``` 53 | 54 | **Advantages:** 55 | - No sudo required for deployment 56 | - Better security isolation 57 | - Easier permission management 58 | 59 | **Requirements:** 60 | - Systemd lingering must be enabled (handled automatically) 61 | - User must have a systemd user instance running 62 | 63 | ### System Services 64 | 65 | System services run as traditional system-wide services. 66 | 67 | ```ruby 68 | set :service_unit_user, :system 69 | ``` 70 | 71 | **Advantages:** 72 | - Starts automatically on boot 73 | - No lingering configuration needed 74 | - Traditional service management 75 | 76 | **Requirements:** 77 | - Sudo permissions for service installation 78 | - Proper User= directive in service file 79 | 80 | ## Service File Generation 81 | 82 | The gem automatically generates systemd service files based on your configuration. The template includes: 83 | 84 | - Proper service dependencies 85 | - Watchdog support (10 second timeout) 86 | - Automatic restart on failure 87 | - Log file configuration 88 | - Environment setup 89 | 90 | ### Generated Service File Location 91 | 92 | - **User services**: `~/.config/systemd/user/_sidekiq_.service` 93 | - **System services**: `/etc/systemd/system/_sidekiq_.service` 94 | 95 | ### Service Naming Convention 96 | 97 | - Default config (`sidekiq.yml`): `_sidekiq_` 98 | - Additional configs: `_sidekiq_.` 99 | 100 | Example: 101 | - `myapp_sidekiq_production` (for sidekiq.yml) 102 | - `myapp_sidekiq_production.sidekiq_critical` (for sidekiq_critical.yml) 103 | 104 | ## Multiple Process Support 105 | 106 | Unlike older versions that used process indices, v3.0.0 uses separate config files for multiple processes: 107 | 108 | ```ruby 109 | # Old approach (no longer supported) 110 | set :sidekiq_processes, 4 # This doesn't work anymore 111 | 112 | # New approach 113 | set :sidekiq_config_files, [ 114 | 'sidekiq.yml', 115 | 'sidekiq_critical.yml', 116 | 'sidekiq_low_priority.yml' 117 | ] 118 | ``` 119 | 120 | Each config file creates a separate systemd service that can be managed independently. 121 | 122 | ## Environment Configuration 123 | 124 | ### Environment Files 125 | 126 | Load environment variables from files: 127 | 128 | ```ruby 129 | set :sidekiq_service_unit_env_files, [ 130 | '/etc/environment', 131 | "#{shared_path}/.env" 132 | ] 133 | ``` 134 | 135 | ### Direct Environment Variables 136 | 137 | Set environment variables directly in the service: 138 | 139 | ```ruby 140 | set :sidekiq_service_unit_env_vars, [ 141 | 'RAILS_ENV=production', 142 | 'MALLOC_ARENA_MAX=2' 143 | ] 144 | ``` 145 | 146 | ## Logging 147 | 148 | ### Modern Systemd (v240+) 149 | 150 | Logs are automatically configured to append to files: 151 | 152 | ```ruby 153 | set :sidekiq_log, -> { File.join(shared_path, 'log', 'sidekiq.log') } 154 | set :sidekiq_error_log, -> { File.join(shared_path, 'log', 'sidekiq.error.log') } 155 | ``` 156 | 157 | ### Viewing Logs 158 | 159 | ```bash 160 | # View service logs 161 | journalctl --user -u myapp_sidekiq_production -f 162 | 163 | # View file logs 164 | tail -f /path/to/shared/log/sidekiq.log 165 | ``` 166 | 167 | ## Deployment Workflow 168 | 169 | ### Initial Setup 170 | 171 | ```bash 172 | cap production sidekiq:install # Creates and enables services 173 | cap production deploy # Deploys and starts services 174 | ``` 175 | 176 | ### Updates 177 | 178 | ```bash 179 | cap production deploy # Automatically restarts services 180 | ``` 181 | 182 | ### Manual Control 183 | 184 | ```bash 185 | cap production sidekiq:start 186 | cap production sidekiq:stop 187 | cap production sidekiq:restart 188 | cap production sidekiq:quiet 189 | ``` 190 | 191 | ## Troubleshooting 192 | 193 | ### Service Won't Start 194 | 195 | 1. Check service status: 196 | ```bash 197 | systemctl --user status myapp_sidekiq_production 198 | ``` 199 | 200 | 2. Check logs: 201 | ```bash 202 | journalctl --user -u myapp_sidekiq_production -n 100 203 | ``` 204 | 205 | 3. Verify lingering (for user services): 206 | ```bash 207 | loginctl show-user $USER | grep Linger 208 | ``` 209 | 210 | ### Permission Issues 211 | 212 | For user services: 213 | - Ensure the deploy user owns all necessary directories 214 | - Check that lingering is enabled 215 | 216 | For system services: 217 | - Verify sudo permissions 218 | - Check service file ownership 219 | 220 | ### Service Stops After Logout 221 | 222 | This indicates lingering is not properly configured. The gem should handle this automatically, but you can manually enable: 223 | 224 | ```bash 225 | sudo loginctl enable-linger $USER 226 | ``` 227 | 228 | ## Migration from Older Versions 229 | 230 | ### From capistrano-sidekiq v2.x 231 | 232 | 1. Remove old configuration: 233 | ```ruby 234 | # Remove these 235 | set :sidekiq_processes, 4 236 | set :sidekiq_options_per_process, [...] 237 | ``` 238 | 239 | 2. Update to new configuration: 240 | ```ruby 241 | # Add these 242 | set :sidekiq_config_files, ['sidekiq.yml'] 243 | install_plugin Capistrano::Sidekiq::Systemd 244 | ``` 245 | 246 | 3. Uninstall old services and install new ones: 247 | ```bash 248 | cap production sidekiq:uninstall 249 | cap production sidekiq:install 250 | ``` 251 | 252 | ### From Monit/Upstart 253 | 254 | 1. Stop and remove old services 255 | 2. Install systemd plugin 256 | 3. Run `cap production sidekiq:install` 257 | 258 | ## Best Practices 259 | 260 | 1. **Use User Services**: Unless you have specific requirements, user services are recommended 261 | 2. **One Config Per Purpose**: Create separate config files for different job types 262 | 3. **Monitor Services**: Set up monitoring for service health 263 | 4. **Resource Limits**: Configure systemd resource limits if needed 264 | 5. **Logging**: Use structured logging and centralized log management 265 | 266 | ## Starting Sidekiq on System Boot 267 | 268 | ### For System Services 269 | 270 | System services automatically start on boot when enabled: 271 | 272 | ```bash 273 | cap production sidekiq:install 274 | cap production sidekiq:enable 275 | ``` 276 | 277 | The service will start automatically after system reboots. 278 | 279 | ### For User Services 280 | 281 | User services require systemd lingering to start without login: 282 | 283 | ```bash 284 | # Enable lingering for the deploy user 285 | sudo loginctl enable-linger deploy 286 | 287 | # Install and enable the service 288 | cap production sidekiq:install 289 | cap production sidekiq:enable 290 | ``` 291 | 292 | ### Verifying Auto-Start 293 | 294 | After reboot, verify services are running: 295 | 296 | ```bash 297 | # For system services 298 | sudo systemctl status myapp_sidekiq_production 299 | 300 | # For user services 301 | systemctl --user status myapp_sidekiq_production 302 | ``` 303 | 304 | ## Automatic Restart on Failure 305 | 306 | The systemd service template includes automatic restart configuration: 307 | 308 | ```ini 309 | [Service] 310 | Restart=on-failure 311 | RestartSec=1 312 | ``` 313 | 314 | This ensures Sidekiq restarts if it crashes. For additional reliability: 315 | 316 | ### Custom Restart Configuration 317 | 318 | Create a custom service template with enhanced restart options: 319 | 320 | ```erb 321 | [Service] 322 | Restart=always 323 | RestartSec=5 324 | StartLimitBurst=5 325 | StartLimitInterval=60s 326 | ``` 327 | 328 | ### Health Monitoring 329 | 330 | Consider adding external monitoring: 331 | 332 | 1. **Systemd Watchdog**: Already configured with `WatchdogSec=10` 333 | 2. **External Monitoring**: Use tools like Monit, God, or custom scripts 334 | 3. **Application Monitoring**: New Relic, Datadog, etc. 335 | 336 | ### Process Management Best Practices 337 | 338 | 1. **Memory Limits**: Prevent memory leaks from affecting the system 339 | ```ruby 340 | set :sidekiq_service_unit_env_vars, ['SIDEKIQ_MAXMEM_MB=1024'] 341 | ``` 342 | 343 | 2. **CPU Limits**: Prevent runaway processes 344 | ```erb 345 | CPUQuota=80% 346 | ``` 347 | 348 | 3. **Restart Notifications**: Get alerted when services restart 349 | ```erb 350 | ExecStopPost=/usr/local/bin/notify-restart.sh 351 | ``` 352 | 353 | ## Advanced Configuration 354 | 355 | ### Custom Service Templates 356 | 357 | Create your own service template: 358 | 359 | ```ruby 360 | set :sidekiq_service_templates_path, 'config/deploy/templates' 361 | ``` 362 | 363 | Place your template at: `config/deploy/templates/sidekiq.service.capistrano.erb` 364 | 365 | ### Custom ExecStart Path 366 | 367 | To customize the command that starts Sidekiq: 368 | 369 | #### Option 1: Using Configuration 370 | 371 | ```ruby 372 | # config/deploy.rb 373 | 374 | # Custom sidekiq binary path 375 | set :sidekiq_command, '/usr/local/bin/sidekiq' 376 | 377 | # Custom bundle path 378 | set :bundle_bins, ['sidekiq'] 379 | set :bundle_path, '/usr/local/bundle' 380 | ``` 381 | 382 | #### Option 2: Custom Service Template 383 | 384 | Create `config/deploy/templates/sidekiq.service.capistrano.erb`: 385 | 386 | ```erb 387 | [Unit] 388 | Description=Sidekiq for <%= "#{fetch(:application)} (#{fetch(:stage)})" %> 389 | After=syslog.target network.target 390 | 391 | [Service] 392 | Type=notify 393 | WatchdogSec=10 394 | WorkingDirectory=<%= current_path %> 395 | 396 | # Custom ExecStart path 397 | ExecStart=/bin/bash -lc 'cd <%= current_path %> && /usr/local/bin/bundle exec sidekiq -e <%= fetch(:sidekiq_env) %> <%= sidekiq_config %>' 398 | 399 | # Or with rbenv 400 | ExecStart=/home/deploy/.rbenv/bin/rbenv exec bundle exec sidekiq -e <%= fetch(:sidekiq_env) %> <%= sidekiq_config %> 401 | 402 | # Or with rvm 403 | ExecStart=/home/deploy/.rvm/bin/rvm default do bundle exec sidekiq -e <%= fetch(:sidekiq_env) %> <%= sidekiq_config %> 404 | 405 | Restart=on-failure 406 | RestartSec=1 407 | 408 | [Install] 409 | WantedBy=multi-user.target 410 | ``` 411 | 412 | #### Option 3: Login Shell Wrapper 413 | 414 | For environments requiring login shell initialization: 415 | 416 | ```erb 417 | ExecStart=/bin/bash -lc '<%= expanded_bundle_path %> exec <%= fetch(:sidekiq_command) %> <%= fetch(:sidekiq_command_args) %> <%= sidekiq_config %>' 418 | ``` 419 | 420 | This ensures all environment variables from `.bashrc`, `.bash_profile`, etc. are loaded. 421 | 422 | ### Resource Limits 423 | 424 | Add to your custom template: 425 | 426 | ``` 427 | [Service] 428 | # Memory limit 429 | MemoryLimit=2G 430 | # CPU quota 431 | CPUQuota=80% 432 | # Restart limits 433 | StartLimitBurst=3 434 | StartLimitInterval=60s 435 | ``` 436 | 437 | ### Dependencies 438 | 439 | Add service dependencies: 440 | 441 | ``` 442 | [Unit] 443 | After=redis.service postgresql.service 444 | Requires=redis.service 445 | ``` 446 | 447 | ## Compatibility 448 | 449 | - **Sidekiq 6.0+**: Full support (removed deprecated features) 450 | - **Systemd 240+**: Full support including log append 451 | - **Systemd 206+**: Basic support (logs via journal only) 452 | - **Ruby 2.5+**: Minimum required version 453 | 454 | ## Known Limitations 455 | 456 | 1. No support for systemd template units (sidekiq@.service) 457 | 2. Each config file creates a separate service 458 | 3. No automatic process count scaling 459 | 4. Requires manual lingering setup on some systems 460 | 461 | These limitations are by design to provide better control and visibility over individual Sidekiq processes. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Capistrano::Sidekiq 2 | 3 | [![Gem Version](https://badge.fury.io/rb/capistrano-sidekiq.svg)](http://badge.fury.io/rb/capistrano-sidekiq) 4 | [![COSS Compliant](https://img.shields.io/badge/COSS-compliant-green.svg)](https://github.com/contriboss/coss_spec) 5 | 6 | Sidekiq integration for Capistrano - providing systemd service management and deployment coordination for Sidekiq 7+. 7 | 8 | **Upgrading from v2.x?** See the [Migration Guide](MIGRATION_FROM_V2.md) for breaking changes and upgrade instructions. 9 | 10 | ## Example Application 11 | 12 | For a complete working example of this gem in action, see the [capistrano-example-app](https://github.com/seuros/capistrano-example-app) which demonstrates: 13 | - Rails 8.0 deployment with Capistrano 14 | - Sidekiq 7.0 with Redis 7+ 15 | - Systemd service management 16 | - rbenv integration 17 | - Complete deployment guide 18 | 19 | ## Installation 20 | 21 | Add to your Gemfile: 22 | 23 | ```ruby 24 | gem 'capistrano-sidekiq', group: :development 25 | ``` 26 | 27 | Then execute: 28 | 29 | ```bash 30 | $ bundle install 31 | ``` 32 | 33 | ## Setup 34 | 35 | Add to your Capfile: 36 | 37 | ```ruby 38 | # Capfile 39 | require 'capistrano/sidekiq' 40 | install_plugin Capistrano::Sidekiq # Default sidekiq tasks (REQUIRED!) 41 | install_plugin Capistrano::Sidekiq::Systemd # Systemd integration (REQUIRED!) 42 | ``` 43 | 44 | **Important:** Both `require` and `install_plugin` lines are necessary. The `require` loads the gem code, while `install_plugin` actually registers the Capistrano tasks. Without `install_plugin`, commands like `cap sidekiq:start` will not be available. 45 | 46 | ## Configuration Options 47 | 48 | ### Basic Settings 49 | 50 | ```ruby 51 | # config/deploy.rb 52 | set :sidekiq_roles, :worker # Default role for Sidekiq processes 53 | set :sidekiq_default_hooks, true # Enable default deployment hooks 54 | set :sidekiq_env, fetch(:rack_env, fetch(:rails_env, fetch(:stage))) # Environment for Sidekiq processes 55 | 56 | # Single config file 57 | set :sidekiq_config_files, ['sidekiq.yml'] 58 | 59 | # Multiple config files for different Sidekiq processes 60 | set :sidekiq_config_files, ['sidekiq.yml', 'sidekiq-high-priority.yml'] 61 | ``` 62 | 63 | ### Shared Configuration with Other Gems 64 | 65 | This gem follows the Capistrano convention of sharing common settings across multiple service gems (e.g., capistrano-puma, capistrano-sidekiq). The following settings are shared: 66 | 67 | - `:service_unit_user` - Determines if services run as system or user services 68 | - `:systemctl_bin` - Path to the systemctl binary 69 | - `:lingering_user` - User for systemd lingering (for user services) 70 | - `:service_unit_env_files` - Shared environment files 71 | - `:service_unit_env_vars` - Shared environment variables 72 | 73 | Each gem can override these with prefixed versions (e.g., `:sidekiq_systemctl_user`). 74 | 75 | ### Advanced Configuration 76 | 77 | ```ruby 78 | # Shared systemd settings (can be used by multiple Capistrano gems like capistrano-puma) 79 | set :service_unit_user, :user # Run as user or system service (:system or :user) 80 | set :systemctl_bin, '/bin/systemctl' # Path to systemctl binary 81 | set :lingering_user, 'deploy' # User to enable lingering for (defaults to :user) 82 | 83 | # Sidekiq-specific overrides (optional - defaults to shared settings above) 84 | set :sidekiq_systemctl_user, :system # Override service_unit_user for Sidekiq only 85 | set :sidekiq_systemctl_bin, '/usr/bin/systemctl' # Override systemctl_bin for Sidekiq only 86 | set :sidekiq_service_unit_name, "custom_sidekiq_#{fetch(:stage)}" # Custom service name 87 | set :sidekiq_lingering_user, 'sidekiq' # Override lingering user for Sidekiq only 88 | 89 | # Environment configuration 90 | set :sidekiq_service_unit_env_files, ['/etc/environment'] # Environment files 91 | set :sidekiq_service_unit_env_vars, [ # Environment variables 92 | 'RAILS_ENV=production', 93 | 'MALLOC_ARENA_MAX=2' 94 | ] 95 | 96 | # Logging configuration 97 | set :sidekiq_log, -> { File.join(shared_path, 'log', 'sidekiq.log') } 98 | set :sidekiq_error_log, -> { File.join(shared_path, 'log', 'sidekiq.error.log') } 99 | 100 | # Command customization 101 | set :sidekiq_command, 'sidekiq' # Use 'sidekiq' or 'sidekiqswarm' for Enterprise 102 | set :sidekiq_command_args, -> { "-e #{fetch(:sidekiq_env)}" } 103 | 104 | # Use login shell to load environment (for rbenv, rvm, etc.) 105 | set :sidekiq_use_login_shell, true 106 | 107 | # Sidekiq Enterprise - Swarm configuration 108 | set :sidekiq_command, 'sidekiqswarm' 109 | set :sidekiq_swarm_env_vars, [ 110 | 'SIDEKIQ_COUNT=5', # Number of processes 111 | 'SIDEKIQ_MAXMEM_MB=768', # Memory limit per process 112 | 'SIDEKIQ_PRELOAD_APP=1' # Preload app for memory efficiency 113 | ] 114 | # Merge swarm env vars with regular env vars 115 | set :sidekiq_service_unit_env_vars, -> { 116 | fetch(:sidekiq_service_unit_env_vars, []) + fetch(:sidekiq_swarm_env_vars, []) 117 | } 118 | ``` 119 | 120 | ### Per-Server Configuration 121 | 122 | You can configure Sidekiq differently for specific servers, allowing you to run different Sidekiq processes with different configurations on different servers. 123 | 124 | #### Basic Per-Server Setup 125 | 126 | ```ruby 127 | # config/deploy/production.rb 128 | server 'worker1.example.com', 129 | roles: [:worker], 130 | sidekiq_config_files: ['sidekiq_high_priority.yml'] 131 | 132 | server 'worker2.example.com', 133 | roles: [:worker], 134 | sidekiq_config_files: ['sidekiq_low_priority.yml'] 135 | ``` 136 | 137 | #### Advanced Per-Server Configuration 138 | 139 | ```ruby 140 | # Different users and multiple processes per server 141 | server 'worker1.example.com', 142 | roles: [:worker], 143 | sidekiq_config_files: ['sidekiq_critical.yml', 'sidekiq_default.yml'], 144 | sidekiq_user: 'sidekiq_critical', 145 | sidekiq_systemctl_user: :system # Run as system service on this server 146 | 147 | server 'worker2.example.com', 148 | roles: [:worker], 149 | sidekiq_config_files: ['sidekiq_batch.yml'], 150 | sidekiq_user: 'sidekiq_batch', 151 | sidekiq_service_unit_env_vars: ['MALLOC_ARENA_MAX=4'] # Server-specific env vars 152 | ``` 153 | 154 | #### How It Works 155 | 156 | 1. **Configuration Files**: Each server can have its own set of `sidekiq_config_files` 157 | 2. **Service Creation**: A separate systemd service is created for each config file 158 | 3. **Service Naming**: Services are named as `_sidekiq_` for the default `sidekiq.yml`, or `_sidekiq_.` for additional configs 159 | 4. **Independent Control**: Each service can be started, stopped, and restarted independently 160 | 161 | #### Example Configurations 162 | 163 | **config/sidekiq_high_priority.yml:** 164 | ```yaml 165 | :concurrency: 10 166 | :queues: 167 | - [critical, 2] 168 | - [high, 1] 169 | ``` 170 | 171 | **config/sidekiq_low_priority.yml:** 172 | ```yaml 173 | :concurrency: 5 174 | :queues: 175 | - [low, 1] 176 | - [default, 1] 177 | ``` 178 | 179 | #### Deployment Commands 180 | 181 | When using per-server configurations, Capistrano will: 182 | - Install the appropriate services on each server during `cap production sidekiq:install` 183 | - Start only the configured services on each server during `cap production sidekiq:start` 184 | - Manage each server's services independently 185 | 186 | You can also target specific servers: 187 | ```bash 188 | cap production sidekiq:restart --hosts=worker1.example.com 189 | ``` 190 | 191 | ## Multiple Processes 192 | 193 | There are two ways to run multiple Sidekiq processes: 194 | 195 | ### Option 1: Multiple Config Files (Recommended) 196 | 197 | Create separate config files for different workloads: 198 | 199 | ```yaml 200 | # config/sidekiq_critical.yml 201 | :concurrency: 5 202 | :queues: 203 | - [critical, 2] 204 | 205 | # config/sidekiq_default.yml 206 | :concurrency: 10 207 | :queues: 208 | - [default, 1] 209 | - [low, 1] 210 | ``` 211 | 212 | Configure in deploy.rb: 213 | ```ruby 214 | set :sidekiq_config_files, ['sidekiq_critical.yml', 'sidekiq_default.yml'] 215 | ``` 216 | 217 | This creates separate services: 218 | - `myapp_sidekiq_production.sidekiq_critical` 219 | - `myapp_sidekiq_production.sidekiq_default` 220 | 221 | Benefits: 222 | - Clear purpose for each process 223 | - Independent scaling and management 224 | - Different configurations per process 225 | - Meaningful service names 226 | 227 | ### Option 2: Sidekiq Enterprise (Sidekiqswarm) 228 | 229 | For simple scaling with identical processes: 230 | 231 | ```ruby 232 | set :sidekiq_command, 'sidekiqswarm' 233 | set :sidekiq_service_unit_env_vars, ['SIDEKIQ_COUNT=10'] 234 | ``` 235 | 236 | This runs 10 identical processes with a single service. 237 | 238 | ### Quick Setup for Multiple Processes 239 | 240 | Use the helper task to generate config files: 241 | 242 | ```bash 243 | # Generate 5 config files 244 | bundle exec cap production sidekiq:helpers:generate_configs[5] 245 | 246 | # This creates: 247 | # - config/sidekiq.yml (critical, high queues) 248 | # - config/sidekiq_1.yml (default, medium queues) 249 | # - config/sidekiq_2.yml (low, background queues) 250 | # - config/sidekiq_3.yml (low, background queues) 251 | # - config/sidekiq_4.yml (low, background queues) 252 | ``` 253 | 254 | Then add to your deploy.rb: 255 | ```ruby 256 | set :sidekiq_config_files, ['sidekiq.yml', 'sidekiq_1.yml', 'sidekiq_2.yml', 'sidekiq_3.yml', 'sidekiq_4.yml'] 257 | ``` 258 | 259 | ## Available Tasks 260 | 261 | ```bash 262 | # View all available tasks 263 | cap -T sidekiq 264 | 265 | # Common commands 266 | cap sidekiq:start # Start Sidekiq 267 | cap sidekiq:stop # Stop Sidekiq (graceful shutdown) 268 | cap sidekiq:restart # Restart Sidekiq 269 | cap sidekiq:quiet # Quiet Sidekiq (stop processing new jobs) 270 | cap sidekiq:install # Install Sidekiq systemd service 271 | cap sidekiq:uninstall # Remove Sidekiq systemd service 272 | cap sidekiq:enable # Enable Sidekiq systemd service 273 | cap sidekiq:disable # Disable Sidekiq systemd service 274 | cap sidekiq:mark_deploy # Mark deployment in Sidekiq metrics (Sidekiq 7+) 275 | 276 | # Helper tasks 277 | cap sidekiq:helpers:generate_configs[3] # Generate 3 config files 278 | cap sidekiq:helpers:show_config # Show current configuration 279 | ``` 280 | 281 | ## Systemd Integration 282 | 283 | For detailed information about systemd integration, see [Systemd Integration Guide](docs/SYSTEMD_INTEGRATION.md). 284 | 285 | ## Deployment Tracking (Sidekiq 7+) 286 | 287 | Sidekiq 7 introduced metrics with deployment tracking. Enable it to see deployment markers in your Sidekiq metrics graphs: 288 | 289 | ### Configuration 290 | 291 | ```ruby 292 | # config/deploy.rb 293 | 294 | # Enable deployment marking 295 | set :sidekiq_mark_deploy, true 296 | 297 | # Optional: Custom deploy label (defaults to git commit description) 298 | set :sidekiq_deploy_label, "v#{fetch(:current_revision)[0..6]} deployed to #{fetch(:stage)}" 299 | ``` 300 | 301 | ### How It Works 302 | 303 | When enabled, the gem will: 304 | 1. Automatically mark deployments after successful deploys 305 | 2. Show vertical red lines in Sidekiq's metrics graphs 306 | 3. Display the deploy label when hovering over the marker 307 | 308 | This helps correlate performance changes with deployments. 309 | 310 | ## Sidekiq Enterprise (Swarm) Support 311 | 312 | This gem supports Sidekiq Enterprise's `sidekiqswarm` command for managing multiple processes with a single service. 313 | 314 | ### Configuration 315 | 316 | ```ruby 317 | # config/deploy.rb 318 | 319 | # Use sidekiqswarm instead of sidekiq 320 | set :sidekiq_command, 'sidekiqswarm' 321 | 322 | # Configure swarm-specific environment variables 323 | set :sidekiq_service_unit_env_vars, [ 324 | 'SIDEKIQ_COUNT=10', # Number of processes to spawn 325 | 'SIDEKIQ_MAXMEM_MB=512', # Memory limit per process 326 | 'SIDEKIQ_PRELOAD_APP=1', # Preload Rails app for memory efficiency 327 | 'RAILS_ENV=production' 328 | ] 329 | 330 | # Optional: Configure shutdown timeout for graceful stops 331 | set :sidekiq_command_args, -> { "-e #{fetch(:sidekiq_env)} -t 30" } 332 | ``` 333 | 334 | ### Benefits of Sidekiqswarm 335 | 336 | - **Single Service**: Manage N processes with one systemd service 337 | - **Memory Efficiency**: Preload app once, fork processes 338 | - **Auto-restart**: Processes that exceed memory limits are automatically restarted 339 | - **Simplified Management**: No need for multiple service files 340 | 341 | ### Per-Server Swarm Configuration 342 | 343 | ```ruby 344 | server 'worker1.example.com', 345 | roles: [:worker], 346 | sidekiq_service_unit_env_vars: ['SIDEKIQ_COUNT=20', 'SIDEKIQ_MAXMEM_MB=1024'] 347 | 348 | server 'worker2.example.com', 349 | roles: [:worker], 350 | sidekiq_service_unit_env_vars: ['SIDEKIQ_COUNT=5', 'SIDEKIQ_MAXMEM_MB=512'] 351 | ``` 352 | 353 | ## Working with Systemd Logs 354 | 355 | View Sidekiq service logs using journalctl: 356 | 357 | ```bash 358 | # View last 100 lines of logs 359 | journalctl -u sidekiq_myapp_production -n 100 360 | 361 | # Follow logs in real-time 362 | journalctl -u sidekiq_myapp_production -f 363 | ``` 364 | 365 | ## Log File Configuration 366 | 367 | ### Modern Systemd (v240+, e.g., Ubuntu 20.04+) 368 | 369 | Log files are configured automatically using the `append:` functionality in the systemd service file. 370 | 371 | ### Legacy Systemd Systems 372 | 373 | For systems with older Systemd versions where `append:` is not supported: 374 | 375 | 1. Sidekiq messages are sent to syslog by default 376 | 2. Configure system logger to filter Sidekiq messages 377 | 378 | ## Example Application 379 | 380 | A complete example application demonstrating the usage of this gem is available at: 381 | https://github.com/seuros/capistrano-example-app 382 | 383 | ## Contributing 384 | 385 | 1. Fork the repository 386 | 2. Create your feature branch (`git checkout -b my-new-feature`) 387 | 3. Commit your changes (`git commit -am 'Add some feature'`) 388 | 4. Push to the branch (`git push origin my-new-feature`) 389 | 5. Create new Pull Request 390 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased](https://github.com/seuros/capistrano-sidekiq/compare/v3.2.0...master) 4 | 5 | ## [3.2.0](https://github.com/seuros/capistrano-sidekiq/compare/v3.1.0...v3.2.0) - 2025-06-22 6 | 7 | ### Changed 8 | - Harmonized interface with capistrano-puma for better ecosystem consistency 9 | - Aligned configuration variable naming patterns 10 | - Unified systemd command execution methods 11 | - Standardized template search order across both gems 12 | - Added documentation reference to example application 13 | 14 | ## [3.1.0](https://github.com/seuros/capistrano-sidekiq/compare/v3.0.0...v3.1.0) - 2025-06-22 15 | 16 | ### Fixed 17 | - Fix undefined method 'as' error by properly calling backend.as (#327) 18 | - Fix inconsistent systemd variable naming (systemctl_user vs sidekiq_systemctl_user) 19 | - Fix systemd lingering configuration issues (#311) 20 | - Fix sidekiq:uninstall to work without sudo for user services (#307) 21 | - Align configuration pattern with capistrano-puma for consistency 22 | 23 | ### Added 24 | - Add sidekiqswarm support for Sidekiq Enterprise 25 | - Add deployment tracking for Sidekiq 7+ metrics (`sidekiq_mark_deploy`) 26 | - Add login shell option for systemd (`sidekiq_use_login_shell`) 27 | - Add configurable sidekiq command (`sidekiq_command`, `sidekiq_command_args`) 28 | - Add helper tasks for generating multiple config files 29 | - Add comprehensive documentation for per-server configuration (#312) 30 | - Add detailed systemd integration guide (#240) 31 | - Add GitHub Actions CI workflow with Ruby 3.2+ support 32 | - Add COSS specification compliance 33 | - Add shared configuration support with other Capistrano service gems 34 | 35 | ### Changed 36 | - Update minimum Ruby version to 3.2+ (required by Sidekiq 7) 37 | - Use consistent sidekiq-prefixed variables for systemd configuration 38 | - Improve README documentation with shared configuration examples 39 | - Update CI to test with Ruby 3.2 and 3.3 40 | - Enhance systemd service template with configurable features 41 | 42 | ## [3.0.0](https://github.com/seuros/capistrano-sidekiq/compare/v2.3.0...v3.0.0) 43 | - Rewrite to match capistrano3-puma api 44 | - Add support for multiple sidekiq configs (processes and queues can be configured with erb) 45 | - Add support to multiple EnvironmentFile 46 | - Add support to multiple EnvironmentVariables 47 | - Default role for sidekiq is now :worker instead of :app 48 | - Remove monit support 49 | - Remove deprecated --index argument for Sidekiq 6.0+ compatibility (#234) 50 | 51 | ## [2.3.0](https://github.com/seuros/capistrano-sidekiq/tree/2.3.0) (2022-05-17) 52 | 53 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.2.0...2.3.0) 54 | 55 | **Merged pull requests:** 56 | 57 | - fix sidekiq processes naming when count is 1 [\#300](https://github.com/seuros/capistrano-sidekiq/pull/300) ([seuros](https://github.com/seuros)) 58 | - Support multiple processes in `sidekiq:install` [\#299](https://github.com/seuros/capistrano-sidekiq/pull/299) ([lloydwatkin](https://github.com/lloydwatkin)) 59 | - fix: monit config template [\#288](https://github.com/seuros/capistrano-sidekiq/pull/288) ([jpickwell](https://github.com/jpickwell)) 60 | 61 | ## [v2.2.0](https://github.com/seuros/capistrano-sidekiq/tree/v2.2.0) (2022-05-16) 62 | 63 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.1.0...v2.2.0) 64 | 65 | **Merged pull requests:** 66 | 67 | - Allow the definition of service\_unit\_name [\#297](https://github.com/seuros/capistrano-sidekiq/pull/297) ([seuros](https://github.com/seuros)) 68 | - restore sidekiq unit env vars [\#295](https://github.com/seuros/capistrano-sidekiq/pull/295) ([tayagi-aim](https://github.com/tayagi-aim)) 69 | - Fix a typo in sidekiq:restart [\#294](https://github.com/seuros/capistrano-sidekiq/pull/294) ([hoppergee](https://github.com/hoppergee)) 70 | 71 | ## [v2.1.0](https://github.com/seuros/capistrano-sidekiq/tree/v2.1.0) (2022-05-15) 72 | 73 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0...v2.1.0) 74 | 75 | **Merged pull requests:** 76 | 77 | - Fix \#253: $HOME is unexpanded in service unit file [\#291](https://github.com/seuros/capistrano-sidekiq/pull/291) ([nikochiko](https://github.com/nikochiko)) 78 | - Update Readme [\#287](https://github.com/seuros/capistrano-sidekiq/pull/287) ([lesliepoolman](https://github.com/lesliepoolman)) 79 | - Fixed sidekiq.service autostart in --user mode [\#285](https://github.com/seuros/capistrano-sidekiq/pull/285) ([michaelkhabarov](https://github.com/michaelkhabarov)) 80 | - README: Add section about older Systemd versions logging [\#284](https://github.com/seuros/capistrano-sidekiq/pull/284) ([64kramsystem](https://github.com/64kramsystem)) 81 | - Avoid using present? [\#282](https://github.com/seuros/capistrano-sidekiq/pull/282) ([frederikspang](https://github.com/frederikspang)) 82 | - Various systemd improvements - Multiple Process Support, Per Process Config, Proper Restarts with timeout and more [\#279](https://github.com/seuros/capistrano-sidekiq/pull/279) ([jclusso](https://github.com/jclusso)) 83 | - Use File.join for systemd file path [\#278](https://github.com/seuros/capistrano-sidekiq/pull/278) ([AndrewSverdrup](https://github.com/AndrewSverdrup)) 84 | - Fix bug in switch\_user and dry up common methods to a helpers module [\#272](https://github.com/seuros/capistrano-sidekiq/pull/272) ([chriscz](https://github.com/chriscz)) 85 | - Update monit integration against Sidekiq 6.0 [\#271](https://github.com/seuros/capistrano-sidekiq/pull/271) ([7up4](https://github.com/7up4)) 86 | - Added sidekiq\_service\_templates\_path to manage custom systemd templates [\#265](https://github.com/seuros/capistrano-sidekiq/pull/265) ([farnsworth](https://github.com/farnsworth)) 87 | - Add sidekiq\_config, sidekiq\_concurrency, and sidekiq\_queue support to systemd [\#262](https://github.com/seuros/capistrano-sidekiq/pull/262) ([ayn](https://github.com/ayn)) 88 | 89 | ## [v2.0.0](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0) (2020-12-19) 90 | 91 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0.beta5...v2.0.0) 92 | 93 | **Merged pull requests:** 94 | 95 | - Upstart update [\#261](https://github.com/seuros/capistrano-sidekiq/pull/261) ([duhast](https://github.com/duhast)) 96 | 97 | ## [v2.0.0.beta5](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0.beta5) (2020-06-25) 98 | 99 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0.beta4...v2.0.0.beta5) 100 | 101 | **Merged pull requests:** 102 | 103 | - Minimal working Upstart plugin [\#255](https://github.com/seuros/capistrano-sidekiq/pull/255) ([duhast](https://github.com/duhast)) 104 | - Capistrano rbenv uses bundle instead of bundler [\#252](https://github.com/seuros/capistrano-sidekiq/pull/252) ([uxxman](https://github.com/uxxman)) 105 | 106 | ## [v2.0.0.beta4](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0.beta4) (2020-06-08) 107 | 108 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0.beta3...v2.0.0.beta4) 109 | 110 | **Merged pull requests:** 111 | 112 | - Fix undefined method as error [\#249](https://github.com/seuros/capistrano-sidekiq/pull/249) ([kyoshidajp](https://github.com/kyoshidajp)) 113 | 114 | ## [v2.0.0.beta3](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0.beta3) (2020-05-26) 115 | 116 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0.beta2...v2.0.0.beta3) 117 | 118 | **Merged pull requests:** 119 | 120 | - Append logs [\#247](https://github.com/seuros/capistrano-sidekiq/pull/247) ([Paprikas](https://github.com/Paprikas)) 121 | - Add "loginctl enable-linger" command to sidekiq systemd install task [\#246](https://github.com/seuros/capistrano-sidekiq/pull/246) ([Paprikas](https://github.com/Paprikas)) 122 | - Setup error output for systemd [\#245](https://github.com/seuros/capistrano-sidekiq/pull/245) ([Paprikas](https://github.com/Paprikas)) 123 | - Use StandardOutput for logging [\#244](https://github.com/seuros/capistrano-sidekiq/pull/244) ([Paprikas](https://github.com/Paprikas)) 124 | 125 | ## [v2.0.0.beta2](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0.beta2) (2020-05-25) 126 | 127 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v2.0.0.beta1...v2.0.0.beta2) 128 | 129 | **Merged pull requests:** 130 | 131 | - Add sidekiq\_service\_unit\_env\_vars option to pass Environment variable… [\#243](https://github.com/seuros/capistrano-sidekiq/pull/243) ([Paprikas](https://github.com/Paprikas)) 132 | 133 | ## [v2.0.0.beta1](https://github.com/seuros/capistrano-sidekiq/tree/v2.0.0.beta1) (2020-05-12) 134 | 135 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v1.0.3...v2.0.0.beta1) 136 | 137 | **Merged pull requests:** 138 | 139 | - Release 2.0.0 [\#236](https://github.com/seuros/capistrano-sidekiq/pull/236) ([seuros](https://github.com/seuros)) 140 | 141 | ## [v1.0.3](https://github.com/seuros/capistrano-sidekiq/tree/v1.0.3) (2019-09-02) 142 | 143 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v1.0.2...v1.0.3) 144 | 145 | **Merged pull requests:** 146 | 147 | - Point readers towards enable lingering for systemd [\#230](https://github.com/seuros/capistrano-sidekiq/pull/230) ([creativetags](https://github.com/creativetags)) 148 | - Update README\#Multiple processes example [\#215](https://github.com/seuros/capistrano-sidekiq/pull/215) ([tamaloa](https://github.com/tamaloa)) 149 | - Add upstart support for start, stop, and quiet [\#208](https://github.com/seuros/capistrano-sidekiq/pull/208) ([tmiller](https://github.com/tmiller)) 150 | - Fix monit config file name missing application [\#205](https://github.com/seuros/capistrano-sidekiq/pull/205) ([xiewenwei](https://github.com/xiewenwei)) 151 | 152 | ## [v1.0.2](https://github.com/seuros/capistrano-sidekiq/tree/v1.0.2) (2018-04-12) 153 | 154 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v1.0.1...v1.0.2) 155 | 156 | ## [v1.0.1](https://github.com/seuros/capistrano-sidekiq/tree/v1.0.1) (2018-04-04) 157 | 158 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v1.0.0...v1.0.1) 159 | 160 | **Merged pull requests:** 161 | 162 | - Fix accounting of pidfiles per process \(when using multiple processes\) [\#197](https://github.com/seuros/capistrano-sidekiq/pull/197) ([jsantos](https://github.com/jsantos)) 163 | - fix fail rolling restart task [\#196](https://github.com/seuros/capistrano-sidekiq/pull/196) ([idekeita](https://github.com/idekeita)) 164 | - README.md - simple edit, highlight known issue with cap 3 [\#192](https://github.com/seuros/capistrano-sidekiq/pull/192) ([westonplatter](https://github.com/westonplatter)) 165 | - Systemd integration [\#171](https://github.com/seuros/capistrano-sidekiq/pull/171) ([baierjan](https://github.com/baierjan)) 166 | - update README with instructions for prepending 'bundle exec' [\#143](https://github.com/seuros/capistrano-sidekiq/pull/143) ([mistidoi](https://github.com/mistidoi)) 167 | - Add deploy failure handling to cap v2 and v3. [\#135](https://github.com/seuros/capistrano-sidekiq/pull/135) ([phillbaker](https://github.com/phillbaker)) 168 | - Support custom monit filename [\#132](https://github.com/seuros/capistrano-sidekiq/pull/132) ([zocoi](https://github.com/zocoi)) 169 | 170 | ## [v1.0.0](https://github.com/seuros/capistrano-sidekiq/tree/v1.0.0) (2018-01-24) 171 | 172 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.20.0...v1.0.0) 173 | 174 | **Merged pull requests:** 175 | 176 | - Spring Cleanup [\#190](https://github.com/seuros/capistrano-sidekiq/pull/190) ([Tensho](https://github.com/Tensho)) 177 | - Convert CHANGELOG to Markdown + Add Unreleased Section [\#189](https://github.com/seuros/capistrano-sidekiq/pull/189) ([Tensho](https://github.com/Tensho)) 178 | - Prepend \_ Before Service Name Index [\#184](https://github.com/seuros/capistrano-sidekiq/pull/184) ([Tensho](https://github.com/Tensho)) 179 | - Christmas Eve Cleaning 🎅 [\#183](https://github.com/seuros/capistrano-sidekiq/pull/183) ([Tensho](https://github.com/Tensho)) 180 | 181 | ## [v0.20.0](https://github.com/seuros/capistrano-sidekiq/tree/v0.20.0) (2017-08-01) 182 | 183 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.10.0...v0.20.0) 184 | 185 | **Merged pull requests:** 186 | 187 | - Use new capistrano DSL for reenable tasks [\#177](https://github.com/seuros/capistrano-sidekiq/pull/177) ([Tensho](https://github.com/Tensho)) 188 | 189 | ## [v0.10.0](https://github.com/seuros/capistrano-sidekiq/tree/v0.10.0) (2016-11-25) 190 | 191 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.5.4...v0.10.0) 192 | 193 | **Merged pull requests:** 194 | 195 | - add documentation; add note to ensure shared/tmp/pids folder exists i… [\#168](https://github.com/seuros/capistrano-sidekiq/pull/168) ([elliotwesoff](https://github.com/elliotwesoff)) 196 | - Make sidekiq:stop task perpetually callable [\#164](https://github.com/seuros/capistrano-sidekiq/pull/164) ([williamn](https://github.com/williamn)) 197 | - Add missing monit default config options to README [\#155](https://github.com/seuros/capistrano-sidekiq/pull/155) ([kirrmann](https://github.com/kirrmann)) 198 | - Documenting sidekiq\_service\_name config option [\#153](https://github.com/seuros/capistrano-sidekiq/pull/153) ([bendilley](https://github.com/bendilley)) 199 | - Fixes identation and Increase documentation with info about :sidekiq\_config [\#131](https://github.com/seuros/capistrano-sidekiq/pull/131) ([ricardokdz](https://github.com/ricardokdz)) 200 | - Respect both local and global puma\_user setting everywhere [\#122](https://github.com/seuros/capistrano-sidekiq/pull/122) ([jhollinger](https://github.com/jhollinger)) 201 | 202 | ## [v0.5.4](https://github.com/seuros/capistrano-sidekiq/tree/v0.5.4) (2015-10-27) 203 | 204 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.5.3...v0.5.4) 205 | 206 | **Merged pull requests:** 207 | 208 | - Change pidfile handling, always add index to pidfile name [\#116](https://github.com/seuros/capistrano-sidekiq/pull/116) ([w1mvy](https://github.com/w1mvy)) 209 | - Move Contributors to separate file. [\#115](https://github.com/seuros/capistrano-sidekiq/pull/115) ([lpaulmp](https://github.com/lpaulmp)) 210 | - Monit configuration respects options\_per\_process [\#113](https://github.com/seuros/capistrano-sidekiq/pull/113) ([kazjote](https://github.com/kazjote)) 211 | - Capistrano 2 fixes [\#109](https://github.com/seuros/capistrano-sidekiq/pull/109) ([wingrunr21](https://github.com/wingrunr21)) 212 | - Use SSHKit command\_map [\#104](https://github.com/seuros/capistrano-sidekiq/pull/104) ([hbin](https://github.com/hbin)) 213 | - Add notice that the pty bug only applies to Capistrano 3. [\#101](https://github.com/seuros/capistrano-sidekiq/pull/101) ([nTraum](https://github.com/nTraum)) 214 | - Add support for different number of processes per host on monit.cap [\#100](https://github.com/seuros/capistrano-sidekiq/pull/100) ([okoriko](https://github.com/okoriko)) 215 | - intial support for sidekiq\_user [\#97](https://github.com/seuros/capistrano-sidekiq/pull/97) ([mcb](https://github.com/mcb)) 216 | 217 | ## [v0.5.3](https://github.com/seuros/capistrano-sidekiq/tree/v0.5.3) (2015-06-25) 218 | 219 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.5.2...v0.5.3) 220 | 221 | **Merged pull requests:** 222 | 223 | - Refactored template\_sidekiq method [\#90](https://github.com/seuros/capistrano-sidekiq/pull/90) ([rstrobl](https://github.com/rstrobl)) 224 | - added ability to operate without sudo [\#89](https://github.com/seuros/capistrano-sidekiq/pull/89) ([dreyks](https://github.com/dreyks)) 225 | - Revert "Add nohup when executing start\_sidekiq command, for a problem… [\#88](https://github.com/seuros/capistrano-sidekiq/pull/88) ([seuros](https://github.com/seuros)) 226 | - Add nohup when executing start\_sidekiq command, for a problem with pty. [\#76](https://github.com/seuros/capistrano-sidekiq/pull/76) ([maruware](https://github.com/maruware)) 227 | - implemented ability to split sidekiq\_roles by count of sidekiq-processes [\#45](https://github.com/seuros/capistrano-sidekiq/pull/45) ([alexyakubenko](https://github.com/alexyakubenko)) 228 | 229 | ## [v0.5.2](https://github.com/seuros/capistrano-sidekiq/tree/v0.5.2) (2015-03-20) 230 | 231 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.5.1...v0.5.2) 232 | 233 | **Merged pull requests:** 234 | 235 | - Set sidekiq\_concurrency default value for cap 2 \(improves pr \#72\). [\#74](https://github.com/seuros/capistrano-sidekiq/pull/74) ([derSascha](https://github.com/derSascha)) 236 | 237 | ## [v0.5.1](https://github.com/seuros/capistrano-sidekiq/tree/v0.5.1) (2015-03-18) 238 | 239 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.5.0...v0.5.1) 240 | 241 | **Merged pull requests:** 242 | 243 | - Support sidekiq\_concurrency option for capistrano 2 [\#72](https://github.com/seuros/capistrano-sidekiq/pull/72) ([mrsimo](https://github.com/mrsimo)) 244 | 245 | ## [v0.5.0](https://github.com/seuros/capistrano-sidekiq/tree/v0.5.0) (2015-03-18) 246 | 247 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.4.0...v0.5.0) 248 | 249 | **Merged pull requests:** 250 | 251 | - Options per process [\#70](https://github.com/seuros/capistrano-sidekiq/pull/70) ([mrsimo](https://github.com/mrsimo)) 252 | - Try execute on the monit.conf mv command [\#69](https://github.com/seuros/capistrano-sidekiq/pull/69) ([bencrouse](https://github.com/bencrouse)) 253 | - Update sidekiq.cap [\#68](https://github.com/seuros/capistrano-sidekiq/pull/68) ([raulbrito](https://github.com/raulbrito)) 254 | - bug fix for generator. [\#66](https://github.com/seuros/capistrano-sidekiq/pull/66) ([zshannon](https://github.com/zshannon)) 255 | - Fix Readme Issues [\#63](https://github.com/seuros/capistrano-sidekiq/pull/63) ([ChuckJHardy](https://github.com/ChuckJHardy)) 256 | - Set default option for sidekiq queue in capistrano 2 script [\#62](https://github.com/seuros/capistrano-sidekiq/pull/62) ([brain-geek](https://github.com/brain-geek)) 257 | - Update Cap2 Defaults to include config file [\#61](https://github.com/seuros/capistrano-sidekiq/pull/61) ([davidlesches](https://github.com/davidlesches)) 258 | - add customizing the monit templates for sidekiq [\#60](https://github.com/seuros/capistrano-sidekiq/pull/60) ([SammyLin](https://github.com/SammyLin)) 259 | - Add queues setup in capistrano2 task [\#57](https://github.com/seuros/capistrano-sidekiq/pull/57) ([brain-geek](https://github.com/brain-geek)) 260 | 261 | ## [v0.4.0](https://github.com/seuros/capistrano-sidekiq/tree/v0.4.0) (2014-11-12) 262 | 263 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.3.8...v0.4.0) 264 | 265 | **Merged pull requests:** 266 | 267 | - Test is Sidekiq actually running when starting with Capistrano 2 [\#54](https://github.com/seuros/capistrano-sidekiq/pull/54) ([Envek](https://github.com/Envek)) 268 | - use release\_path instead of current\_path [\#50](https://github.com/seuros/capistrano-sidekiq/pull/50) ([flyerhzm](https://github.com/flyerhzm)) 269 | - Typo [\#48](https://github.com/seuros/capistrano-sidekiq/pull/48) ([binyamindavid](https://github.com/binyamindavid)) 270 | - Fix descriptions of monit tasks [\#47](https://github.com/seuros/capistrano-sidekiq/pull/47) ([jgeiger](https://github.com/jgeiger)) 271 | 272 | ## [v0.3.8](https://github.com/seuros/capistrano-sidekiq/tree/v0.3.8) (2014-09-22) 273 | 274 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.3.7...v0.3.8) 275 | 276 | **Merged pull requests:** 277 | 278 | - Improve @bensie pull request + unmonitor monit while deploy [\#46](https://github.com/seuros/capistrano-sidekiq/pull/46) ([Saicheg](https://github.com/Saicheg)) 279 | 280 | ## [v0.3.7](https://github.com/seuros/capistrano-sidekiq/tree/v0.3.7) (2014-09-01) 281 | 282 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.3.6...v0.3.7) 283 | 284 | **Merged pull requests:** 285 | 286 | - Start Sidekiq as daemon from Monit [\#40](https://github.com/seuros/capistrano-sidekiq/pull/40) ([dpaluy](https://github.com/dpaluy)) 287 | - Sidekiq is properly restarted after a crash when deploying with Capsitrano2 [\#39](https://github.com/seuros/capistrano-sidekiq/pull/39) ([tribble](https://github.com/tribble)) 288 | 289 | ## [v0.3.6](https://github.com/seuros/capistrano-sidekiq/tree/v0.3.6) (2014-08-08) 290 | 291 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.3.5...v0.3.6) 292 | 293 | **Merged pull requests:** 294 | 295 | - If :sidekiq\_config is set, Monit template should use it to start the ser... [\#35](https://github.com/seuros/capistrano-sidekiq/pull/35) ([joshmyers](https://github.com/joshmyers)) 296 | - replace deploy:restart with deploy:publishing for capistrano 3.1 [\#34](https://github.com/seuros/capistrano-sidekiq/pull/34) ([flyerhzm](https://github.com/flyerhzm)) 297 | - Fix: test with spaces ignores within [\#33](https://github.com/seuros/capistrano-sidekiq/pull/33) ([rogercampos](https://github.com/rogercampos)) 298 | - Added \_cset for :sidekiq\_tag [\#32](https://github.com/seuros/capistrano-sidekiq/pull/32) ([OscarBarrett](https://github.com/OscarBarrett)) 299 | 300 | ## [v0.3.5](https://github.com/seuros/capistrano-sidekiq/tree/v0.3.5) (2014-07-25) 301 | 302 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.3.4...v0.3.5) 303 | 304 | **Merged pull requests:** 305 | 306 | - Allow use of sidekiq\_tag for capistrano2 [\#30](https://github.com/seuros/capistrano-sidekiq/pull/30) ([OscarBarrett](https://github.com/OscarBarrett)) 307 | 308 | ## [v0.3.4](https://github.com/seuros/capistrano-sidekiq/tree/v0.3.4) (2014-07-09) 309 | 310 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/v0.1.0...v0.3.4) 311 | 312 | **Merged pull requests:** 313 | 314 | - Added concurrency option [\#26](https://github.com/seuros/capistrano-sidekiq/pull/26) ([ungsophy](https://github.com/ungsophy)) 315 | - Fix bug with process index in monit task [\#21](https://github.com/seuros/capistrano-sidekiq/pull/21) ([0x616E676572](https://github.com/0x616E676572)) 316 | - You can now use signals to quiet/stop sidekiq, much faster. [\#18](https://github.com/seuros/capistrano-sidekiq/pull/18) ([penso](https://github.com/penso)) 317 | - Check that current\_path exists before stopping [\#16](https://github.com/seuros/capistrano-sidekiq/pull/16) ([alexdunae](https://github.com/alexdunae)) 318 | - search pid files in correct directory [\#12](https://github.com/seuros/capistrano-sidekiq/pull/12) ([levinalex](https://github.com/levinalex)) 319 | - Rolling restart [\#7](https://github.com/seuros/capistrano-sidekiq/pull/7) ([jlecour](https://github.com/jlecour)) 320 | 321 | ## [v0.1.0](https://github.com/seuros/capistrano-sidekiq/tree/v0.1.0) (2014-03-24) 322 | 323 | [Full Changelog](https://github.com/seuros/capistrano-sidekiq/compare/07b9d97f5bcf08af43baec0924bb088a6486f31c...v0.1.0) 324 | 325 | **Merged pull requests:** 326 | 327 | - Cleaner version checking [\#6](https://github.com/seuros/capistrano-sidekiq/pull/6) ([ghost](https://github.com/ghost)) 328 | - More robust version checking [\#4](https://github.com/seuros/capistrano-sidekiq/pull/4) ([jlecour](https://github.com/jlecour)) 329 | - More explicit start command [\#3](https://github.com/seuros/capistrano-sidekiq/pull/3) ([jlecour](https://github.com/jlecour)) 330 | - Improve pid and log files settings [\#1](https://github.com/seuros/capistrano-sidekiq/pull/1) ([jlecour](https://github.com/jlecour)) 331 | 332 | 333 | 334 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 335 | --------------------------------------------------------------------------------