-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sidekiq wrappers. #1689
Open
eugenk
wants to merge
15
commits into
staging
Choose a base branch
from
1646-services_on_ontohub_org
base: staging
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add sidekiq wrappers. #1689
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
de780cf
Add sidekiq wrappers.
eugenk f4cfa26
Freeze mutable objects assigned to constants.
eugenk 9dd516a
Use CWD if no workdir is given.
eugenk e096b8b
Make timeout a parameter.
eugenk 93f48bd
Only have one sidekiq wrapper for all processes.
eugenk 3e17b8d
Make the environment a parameter.
eugenk 2a78ce2
Use full name as hash key.
eugenk 15890c0
Use daemons gem to daemonize sidekiq_wrapper.
eugenk 5b067f7
Improve synopsis.
eugenk c6fa541
Adjust eye config to svcadm.
eugenk 2d414f7
Specify pidfiles per process.
eugenk a462156
Fix eye config.
eugenk c3b28de
Fix pids
eugenk 32030a6
Stop other processes when one died.
eugenk 0f4089c
Exit with proper exit code.
eugenk File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require 'optparse' | ||
require_relative '../lib/environment_light.rb' | ||
|
||
RAILS_ROOT ||= File.expand_path('../..', __FILE__).freeze | ||
SIDEKIQ_EXECUTABLE = File.join(RAILS_ROOT, 'bin/sidekiq').freeze | ||
|
||
# Parse options | ||
def parse_options | ||
options = {environment: 'production', | ||
workdir: Dir.pwd, | ||
timeout: 15} | ||
OptionParser.new do |opts| | ||
opts.banner = "Usage: #{File.basename(__FILE__)} [options]" | ||
|
||
opts.on('-eMANDATORY', '--environment=Rails env', | ||
"Set Rails environment (default: #{options[:environment]})") do |e| | ||
options[:environment] = e | ||
end | ||
|
||
opts.on('-wMANDATORY', '--workdir=directory', | ||
'Set work directory (default: CWD)') do |w| | ||
options[:workdir] = w | ||
end | ||
|
||
opts.on('-tMANDATORY', '--timeout=seconds', | ||
'Set timeout in seconds until sidekiq jobs are killed at '\ | ||
"sidekiq shutdown (default: #{options[:timeout]})") do |t| | ||
options[:timeout] = t | ||
end | ||
end.parse! | ||
options | ||
end | ||
|
||
def run_process(options, arguments, name) | ||
Process.spawn(SIDEKIQ_EXECUTABLE, *arguments, | ||
'--require', RAILS_ROOT, | ||
'--environment', options[:environment], | ||
'--timeout', options[:timeout].to_s, | ||
'--pidfile', "#{File.join(options[:workdir], name)}.pid", | ||
'--logfile', "#{File.join(options[:workdir], name)}.log") | ||
end | ||
|
||
def wait_for_process(statuses, wait_threads, name, pid, pids) | ||
wait_threads << Thread.new do | ||
_pid, status = Process.wait2(pid) | ||
statuses << status | ||
stop_all_processes(name, pid, pids) | ||
end | ||
end | ||
|
||
def send_signal(signal, pid) | ||
Process.kill(signal, pid) | ||
rescue Errno::ESRCH | ||
$stderr.puts "Could not send signal: Process #{pid} was already terminated." | ||
end | ||
|
||
$stopped_all = false | ||
def stop_all_processes(name_dead, pid_dead, pids) | ||
unless $stopped_all | ||
pids.each do |name, pid| | ||
unless pid == pid_dead | ||
$stderr.puts "Stopping #{name} because one sidekiq process"\ | ||
"(#{name_dead}) exited..." | ||
send_signal('TERM', pid) | ||
end | ||
end | ||
end | ||
$stopped_all = true | ||
end | ||
|
||
def exit_with_status(statuses) | ||
if statuses.all? { |status| status.exited? && status.success? } | ||
exit 0 | ||
else | ||
exit 1 | ||
end | ||
end | ||
|
||
def hets_queue_thread_count | ||
# One thread per configured hets instance, minus one for the sequential queue. | ||
[1, Settings.hets.instance_urls.size - 1].max | ||
end | ||
|
||
options = parse_options | ||
pids = {} | ||
processes = | ||
{:'sidekiq-hets' => %W(--queue prioirty_push,25 | ||
--queue hets,5 | ||
--queue hets-migration,1 | ||
--concurrency #{hets_queue_thread_count}), | ||
:'sidekiq-sequential' => %w(--queue sequential | ||
--concurrency 1), | ||
:'sidekiq-default' => %w(--queue default | ||
--queue hets_load_balancing | ||
--concurrency 5)} | ||
|
||
# USR1: terminate in the near future | ||
# USR2: reopen logs | ||
# TERM: terminate in the near future, at most after `timeout` seconds | ||
%w(USR1 USR2 TERM).each do |signal| | ||
Signal.trap(signal) do | ||
pids.each do |name, pid| | ||
$stdout.puts "Sending #{signal} to #{name}..." | ||
send_signal(signal, pid) | ||
end | ||
end | ||
end | ||
|
||
processes.each do |name, arguments| | ||
pids[name] = run_process(options, arguments, "#{name}") | ||
end | ||
|
||
wait_threads = [] | ||
statuses = [] | ||
pids.each do |name, pid| | ||
wait_for_process(statuses, wait_threads, name, pid, pids) | ||
end | ||
wait_threads.each(&:join) | ||
|
||
exit_with_status(statuses) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require 'daemons' | ||
|
||
RAILS_ROOT = File.expand_path('../..', __FILE__).freeze | ||
Daemons.run(File.join(RAILS_ROOT, 'bin/sidekiq_wrapper'), | ||
dir_mode: :normal, | ||
dir: File.join(RAILS_ROOT, 'tmp/pids')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,26 @@ | ||
require 'fileutils' | ||
require File.expand_path('../../../lib/environment_light_with_hets.rb', __FILE__) | ||
require File.expand_path('../eye_methods.rb', __FILE__) | ||
RAILS_ROOT = File.join(File.dirname(__FILE__), '../..') | ||
RAILS_ENV = ENV['RAILS_ENV'] || 'production' | ||
SVCADM = '/usr/sbin/svcadm' | ||
|
||
SIDEKIQ_BASE = '/var/sidekiq' | ||
Eye.config do | ||
logger "#{Rails.root}/log/eye.log" | ||
end | ||
|
||
def hets_queue_thread_count | ||
# One thread per configured hets instance, minus one for the sequential queue. | ||
[1, Settings.hets.instance_urls.size - 1].max | ||
logger "#{RAILS_ROOT}/log/eye.log" | ||
end | ||
|
||
Eye.application :ontohub do | ||
working_dir Rails.root.to_s | ||
env 'RAILS_ENV' => Rails.env | ||
env 'PID_DIR' => Rails.root.join('tmp', 'pids').to_s | ||
|
||
# Create PID dir | ||
FileUtils.mkdir_p(env['PID_DIR']) | ||
|
||
group :sidekiq do | ||
# prioritize queues: | ||
# priority_push 5x as high as hets, which is 5x as high as hets-migration | ||
sidekiq_process self, :"sidekiq-hets", | ||
['priority_push,25', 'hets,5', 'hets-migration,1'], | ||
hets_queue_thread_count | ||
|
||
# one multithreaded worker for the default queue and hets_load_balancing | ||
sidekiq_process self, :'sidekiq-default', ['default', 'hets_load_balancing'], 5 | ||
|
||
# one worker for the sequential queue | ||
sidekiq_process self, :'sidekiq-sequential', 'sequential', 1 | ||
end | ||
|
||
group :hets do | ||
Settings.hets.instance_urls.each do |url| | ||
if url.match(%r{\Ahttps?://(localhost|127.0.0.1|0.0.0.0|::1)}) | ||
hets_process self, URI(url).port | ||
end | ||
working_dir RAILS_ROOT | ||
env 'RAILS_ENV' => RAILS_ENV | ||
env 'PID_DIR' => File.join(RAILS_ROOT, 'tmp/pids') | ||
|
||
{git: File.join(env['PID_DIR'], 'git.pid'), | ||
hets: File.join(env['PID_DIR'], 'hets.pid'), | ||
puma: File.join(env['PID_DIR'], 'puma.pid'), | ||
sidekiq: File.join(SIDEKIQ_BASE, 'master.pid')}.each do |service, pidfile| | ||
process service do | ||
daemonize false | ||
pid_file pidfile | ||
start_command "#{SVCADM} enable -s #{service}" | ||
stop_command "#{SVCADM} disable -s #{service}" | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW: dict lookup MANDATORY!
Also as a general rule of thumb: In synopsis, usage infos the option value names should indicate its "type", e.g. -w directory, -t seconds. The description should just include '(mandatory)' or '(optional)' if needed. Usually it is not, because the default value should be mentioned and than it is clear, that it is 'optional'. For arg-less options the name option indicates, that it is _option_al and thus doesn't need to be explicitly mentioned. So only in very rare cases or combination of options may require, that 'mandatory' appears in documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
MANDATORY
is Ruby'soptparse
's way to say that if-w
is used, then a value must be specified. This does not say that you have to use-w
at all.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Admins usually have no notion of ill/senseless optparse documentation. However, they know [indirectly] http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html by reading man pages and usage synopsis from native Unix utilities ...