Module: ProcessBot::Capistrano::SidekiqHelpers

Included in:
Sidekiq
Defined in:
lib/process_bot/capistrano/sidekiq_helpers.rb

Overview

rubocop:disable Metrics/ModuleLength

Instance Method Summary collapse

Instance Method Details

#expanded_bundle_pathObject



108
109
110
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 108

def expanded_bundle_path
  backend.capture(:echo, SSHKit.config.command_map[:bundle]).strip
end

#parse_process_bot_process_from_ps(processes_output) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 83

def parse_process_bot_process_from_ps(processes_output)
  processes = []
  processes_output.scan(/^\s*(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+ProcessBot (\{([^\n]+?)\})$/).each do |process_output|
    process_bot_data = JSON.parse(process_output[4])
    process_bot_pid = process_output[0]
    process_bot_data["process_bot_pid"] = process_bot_pid

    processes << process_bot_data
  end

  processes
end

#process_bot_command(process_bot_data, command) ⇒ Object

rubocop:disable Metrics/AbcSize



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 35

def process_bot_command(process_bot_data, command) # rubocop:disable Metrics/AbcSize
  raise "No port in process bot data? #{process_bot_data}" unless process_bot_data["port"]

  mode = "exec"

  if mode == "runner"
    args = {command: command, port: process_bot_data.fetch("port")}

    if command == :graceful && !fetch(:process_bot_wait_for_gracefully_stopped).nil?
      args["wait_for_gracefully_stopped"] = fetch(:process_bot_wait_for_gracefully_stopped)
    end

    escaped_args = JSON.generate(args).gsub("\"", "\\\"")
    rails_runner_command = "require 'process_bot'; ProcessBot::Process.new(ProcessBot::Options.from_args(#{escaped_args})).execute!"

    backend_command = "cd #{release_path} && " \
      "#{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec rails runner \"#{rails_runner_command}\""
  elsif mode == "exec"
    backend_command = "cd #{release_path} && " \
      "#{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec process_bot " \
      "--command #{command} " \
      "--port #{process_bot_data.fetch("port")}"

    if command == :graceful && !fetch(:process_bot_wait_for_gracefully_stopped).nil?
      backend_command << " --wait-for-gracefully-stopped #{fetch(:process_bot_wait_for_gracefully_stopped)}"
    end
  else
    raise "Unknown mode: #{mode}"
  end

  backend.execute backend_command
end

#running_process_bot_processesObject



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 68

def running_process_bot_processes
  sidekiq_app_name = fetch(:sidekiq_app_name, fetch(:application))
  raise "No :sidekiq_app_name was set" unless sidekiq_app_name

  begin
    processes_output = backend.capture("ps a | grep ProcessBot | grep sidekiq | grep -v '/usr/bin/SCREEN' | grep '#{Regexp.escape(sidekiq_app_name)}'")
  rescue SSHKit::Command::Failed
    # Fails when output is empty (when no processes found through grep)
    puts "No ProcessBot Sidekiq processes found"
    return []
  end

  parse_process_bot_process_from_ps(processes_output)
end

#sidekiq_concurrencyObject



12
13
14
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 12

def sidekiq_concurrency
  "--concurrency #{fetch(:sidekiq_concurrency)}" if fetch(:sidekiq_concurrency)
end

#sidekiq_configObject



8
9
10
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 8

def sidekiq_config
  "--config #{fetch(:sidekiq_config)}" if fetch(:sidekiq_config)
end

#sidekiq_logfileObject



22
23
24
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 22

def sidekiq_logfile
  fetch(:sidekiq_log)
end

#sidekiq_queuesObject



16
17
18
19
20
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 16

def sidekiq_queues
  Array(fetch(:sidekiq_queue)).map do |queue|
    "--queue #{queue}"
  end.join(" ")
end

#sidekiq_requireObject



4
5
6
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 4

def sidekiq_require
  "--require #{fetch(:sidekiq_require)}" if fetch(:sidekiq_require)
end

#sidekiq_user(role = nil) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 96

def sidekiq_user(role = nil)
  if role.nil?
    fetch(:sidekiq_user)
  else
    properties = role.properties
    properties.fetch(:sidekiq_user) || # local property for sidekiq only
      fetch(:sidekiq_user) ||
      properties.fetch(:run_as) || # global property across multiple capistrano gems
      role.user
  end
end

#start_sidekiq(idx = 0) ⇒ Object

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 112

def start_sidekiq(idx = 0) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
  releases = backend.capture(:ls, "-x", releases_path).split
  releases << release_timestamp.to_s if release_timestamp
  releases.uniq

  latest_release_version = releases.last
  raise "Invalid release timestamp: #{release_timestamp}" unless latest_release_version

  args = [
    "--command", "start",
    "--id", "sidekiq-#{latest_release_version}-#{idx}",
    "--application", fetch(:sidekiq_app_name, fetch(:application)),
    "--handler", "sidekiq",
    "--bundle-prefix", SSHKit.config.command_map.prefix[:bundle].join(" "),
    "--sidekiq-environment", fetch(:sidekiq_env),
    "--port", idx + 7050,
    "--release-path", release_path
  ]

  # Use screen for logging everything which is why this is disabled
  # args += ["--log-file-path", fetch(:sidekiq_log)] if fetch(:sidekiq_log)

  args += ["--sidekiq-require", fetch(:sidekiq_require)] if fetch(:sidekiq_require)
  args += ["--sidekiq-tag", fetch(:sidekiq_tag)] if fetch(:sidekiq_tag)
  args += ["--sidekiq-queues", Array(fetch(:sidekiq_queue)).join(",")] if fetch(:sidekiq_queue)
  args += ["--sidekiq-config", fetch(:sidekiq_config)] if fetch(:sidekiq_config)
  args += ["--sidekiq-concurrency", fetch(:sidekiq_concurrency)] if fetch(:sidekiq_concurrency)
  if (process_options = fetch(:sidekiq_options_per_process))
    args += process_options[idx]
  end
  args += fetch(:sidekiq_options) if fetch(:sidekiq_options)

  screen_args = ["-dmS process-bot--sidekiq--#{idx}-#{latest_release_version}"]

  if (process_bot_sidekiq_log = fetch(:process_bot_sidekig_log))
    screen_args << "-L -Logfile #{process_bot_sidekiq_log}_#{latest_release_version}_#{idx}.log"
  elsif fetch(:sidekiq_log)
    screen_args << "-L -Logfile #{fetch(:sidekiq_log)}"
  end

  process_bot_args = args.compact.map { |arg| "\"#{arg}\"" }

  command = "/usr/bin/screen #{screen_args.join(" ")} " \
    "bash -c 'cd #{release_path} && exec #{SSHKit.config.command_map.prefix[:bundle].join(" ")} bundle exec process_bot #{process_bot_args.join(" ")}'"

  puts "WARNING: A known bug prevents Sidekiq from starting when pty is set (which it is)" if fetch(:pty)
  puts "ProcessBot Sidekiq command: #{command}"

  backend.execute command
end

#switch_user(role, &block) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/process_bot/capistrano/sidekiq_helpers.rb', line 26

def switch_user(role, &block)
  su_user = sidekiq_user(role)
  if su_user == role.user
    yield
  else
    as su_user, &block
  end
end