Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
97d2d909
Commit
97d2d909
authored
Dec 22, 2016
by
Valery Sizov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ee into ce_upstream
parents
f59e2b01
e27ebba5
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
80 additions
and
47 deletions
+80
-47
bin/sidekiq-cluster
bin/sidekiq-cluster
+0
-1
lib/gitlab/sidekiq_cluster.rb
lib/gitlab/sidekiq_cluster.rb
+39
-21
lib/gitlab/sidekiq_cluster/cli.rb
lib/gitlab/sidekiq_cluster/cli.rb
+17
-6
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
+2
-2
spec/lib/gitlab/sidekiq_cluster_spec.rb
spec/lib/gitlab/sidekiq_cluster_spec.rb
+22
-17
No files found.
bin/sidekiq-cluster
View file @
97d2d909
#!/usr/bin/env ruby
require
'optparse'
require
'thread'
require_relative
'../lib/gitlab/sidekiq_cluster'
require_relative
'../lib/gitlab/sidekiq_cluster/cli'
...
...
lib/gitlab/sidekiq_cluster.rb
View file @
97d2d909
require
'open3'
module
Gitlab
module
SidekiqCluster
# The signals that should terminate both the master and workers.
...
...
@@ -41,15 +39,15 @@ module Gitlab
false
end
def
self
.
signal_
threads
(
threa
ds
,
signal
)
threads
.
each
{
|
thread
|
signal
(
thread
.
pid
,
signal
)
}
def
self
.
signal_
processes
(
pi
ds
,
signal
)
pids
.
each
{
|
pid
|
signal
(
pid
,
signal
)
}
end
def
self
.
parse_queues
(
array
)
array
.
map
{
|
chunk
|
chunk
.
split
(
','
)
}
end
# Starts Sidekiq workers for the pairs of
thread
s.
# Starts Sidekiq workers for the pairs of
processe
s.
#
# Example:
#
...
...
@@ -61,29 +59,49 @@ module Gitlab
# queues - An Array containing Arrays. Each sub Array should specify the
# queues to use for a single process.
#
# Returns an Array containing the threads monitoring each process.
def
self
.
start
(
queues
,
env
)
queues
.
map
{
|
pair
|
start_sidekiq
(
pair
,
env
)
}
# directory - The directory of the Rails application.
#
# Returns an Array containing the PIDs of the started processes.
def
self
.
start
(
queues
,
env
,
directory
=
Dir
.
pwd
)
queues
.
map
{
|
pair
|
start_sidekiq
(
pair
,
env
,
directory
)
}
end
# Starts a Sidekiq process that processes _only_ the given queues.
def
self
.
start_sidekiq
(
queues
,
env
)
#
# Returns the PID of the started process.
def
self
.
start_sidekiq
(
queues
,
env
,
directory
=
Dir
.
pwd
)
switches
=
queues
.
map
{
|
q
|
"-q
#{
q
}
,1"
}
Open3
.
popen3
({
'ENABLE_SIDEKIQ_CLUSTER'
=>
'1'
},
pid
=
Process
.
spawn
(
{
'ENABLE_SIDEKIQ_CLUSTER'
=>
'1'
},
'bundle'
,
'exec'
,
'sidekiq'
,
"-c
#{
queues
.
length
+
1
}
"
,
"-e
#{
env
}
"
,
"-gqueues:
#{
queues
.
join
(
', '
)
}
"
,
*
switches
).
last
"-r
#{
directory
}
"
,
*
switches
,
err:
$stderr
,
out:
$stdout
)
wait_async
(
pid
)
pid
end
# Waits for the given process to complete using a separate thread.
def
self
.
wait_async
(
pid
)
Thread
.
new
do
Process
.
wait
(
pid
)
rescue
Errno
::
ECHILD
end
end
# Returns true if all the processes
/threads
are alive.
def
self
.
all_alive?
(
threa
ds
)
threads
.
each
do
|
threa
d
|
return
false
unless
signal
(
thread
.
pid
,
0
)
# Returns true if all the processes are alive.
def
self
.
all_alive?
(
pi
ds
)
pids
.
each
do
|
pi
d
|
return
false
unless
signal
(
pid
,
0
)
end
true
...
...
lib/gitlab/sidekiq_cluster/cli.rb
View file @
97d2d909
require
'optparse'
require
'logger'
require
'time'
module
Gitlab
module
SidekiqCluster
...
...
@@ -11,8 +12,14 @@ module Gitlab
@pid
=
nil
@interval
=
5
@alive
=
true
@
thread
s
=
[]
@
processe
s
=
[]
@logger
=
Logger
.
new
(
log_output
)
@rails_path
=
Dir
.
pwd
# Use a log format similar to Sidekiq to make parsing/grepping easier.
@logger
.
formatter
=
proc
do
|
level
,
date
,
program
,
message
|
"
#{
date
.
utc
.
iso8601
(
3
)
}
#{
Process
.
pid
}
TID-
#{
Thread
.
current
.
object_id
.
to_s
(
36
)
}
#{
level
}
:
#{
message
}
\n
"
end
end
def
run
(
argv
=
ARGV
)
...
...
@@ -27,7 +34,7 @@ module Gitlab
@logger
.
info
(
"Starting cluster with
#{
queues
.
length
}
processes"
)
@
threads
=
SidekiqCluster
.
start
(
queues
,
@environment
)
@
processes
=
SidekiqCluster
.
start
(
queues
,
@environment
,
@rails_path
)
write_pid
trap_signals
...
...
@@ -41,11 +48,11 @@ module Gitlab
def
trap_signals
SidekiqCluster
.
trap_terminate
do
|
signal
|
@alive
=
false
SidekiqCluster
.
signal_
threads
(
@thread
s
,
signal
)
SidekiqCluster
.
signal_
processes
(
@processe
s
,
signal
)
end
SidekiqCluster
.
trap_forward
do
|
signal
|
SidekiqCluster
.
signal_
threads
(
@thread
s
,
signal
)
SidekiqCluster
.
signal_
processes
(
@processe
s
,
signal
)
end
end
...
...
@@ -53,12 +60,12 @@ module Gitlab
while
@alive
sleep
(
@interval
)
unless
SidekiqCluster
.
all_alive?
(
@
thread
s
)
unless
SidekiqCluster
.
all_alive?
(
@
processe
s
)
# If a child process died we'll just terminate the whole cluster. It's up to
# runit and such to then restart the cluster.
@logger
.
info
(
'A worker terminated, shutting down the cluster'
)
SidekiqCluster
.
signal_
threads
(
@thread
s
,
:TERM
)
SidekiqCluster
.
signal_
processes
(
@processe
s
,
:TERM
)
break
end
end
...
...
@@ -82,6 +89,10 @@ module Gitlab
@pid
=
pid
end
opt
.
on
(
'-r'
,
'--require PATH'
,
'Location of the Rails application'
)
do
|
path
|
@rails_path
=
path
end
opt
.
on
(
'-i'
,
'--interval INT'
,
'The number of seconds to wait between worker checks'
)
do
|
int
|
@interval
=
int
.
to_i
end
...
...
spec/lib/gitlab/sidekiq_cluster/cli_spec.rb
View file @
97d2d909
...
...
@@ -51,13 +51,13 @@ describe Gitlab::SidekiqCluster::CLI do
end
describe
'#start_loop'
do
it
'runs until one of the
thread
s has been terminated'
do
it
'runs until one of the
processe
s has been terminated'
do
allow
(
cli
).
to
receive
(
:sleep
).
with
(
a_kind_of
(
Numeric
))
expect
(
Gitlab
::
SidekiqCluster
).
to
receive
(
:all_alive?
).
with
(
an_instance_of
(
Array
)).
and_return
(
false
)
expect
(
Gitlab
::
SidekiqCluster
).
to
receive
(
:signal_
thread
s
).
expect
(
Gitlab
::
SidekiqCluster
).
to
receive
(
:signal_
processe
s
).
with
(
an_instance_of
(
Array
),
:TERM
)
cli
.
start_loop
...
...
spec/lib/gitlab/sidekiq_cluster_spec.rb
View file @
97d2d909
...
...
@@ -40,13 +40,11 @@ describe Gitlab::SidekiqCluster do
end
end
describe
'.signal_
thread
s'
do
describe
'.signal_
processe
s'
do
it
'sends a signal to every thread'
do
thread
=
double
(
:thread
,
pid:
1
)
expect
(
described_class
).
to
receive
(
:signal
).
with
(
1
,
:INT
)
expect
(
described_class
).
to
receive
(
:signal
).
with
(
thread
.
pid
,
:INT
)
described_class
.
signal_threads
([
thread
],
:INT
)
described_class
.
signal_processes
([
1
],
:INT
)
end
end
...
...
@@ -60,41 +58,48 @@ describe Gitlab::SidekiqCluster do
describe
'.start'
do
it
'starts Sidekiq with the given queues and environment'
do
expect
(
described_class
).
to
receive
(
:start_sidekiq
).
ordered
.
with
(
%w(foo)
,
:production
)
ordered
.
with
(
%w(foo)
,
:production
,
'foo/bar'
)
expect
(
described_class
).
to
receive
(
:start_sidekiq
).
ordered
.
with
(
%w(bar baz)
,
:production
)
ordered
.
with
(
%w(bar baz)
,
:production
,
'foo/bar'
)
described_class
.
start
([
%w(foo)
,
%w(bar baz)
],
:production
)
described_class
.
start
([
%w(foo)
,
%w(bar baz)
],
:production
,
'foo/bar'
)
end
end
describe
'.start_sidekiq'
do
it
'starts a Sidekiq process'
do
thread
=
double
(
:thread
,
pid:
1
)
allow
(
Process
).
to
receive
(
:spawn
).
and_return
(
1
)
expect
(
described_class
).
to
receive
(
:wait_async
).
with
(
1
)
expect
(
described_class
.
start_sidekiq
(
%w(foo)
,
:production
)).
to
eq
(
1
)
end
end
allow
(
Open3
).
to
receive
(
:popen3
).
and_return
([
double
(
:stdout
),
double
(
:stderr
),
double
(
:stdin
),
thread
])
describe
'.wait_async'
do
it
'waits for a process in a separate thread'
do
thread
=
described_class
.
wait_async
(
Process
.
spawn
(
'true'
))
expect
(
described_class
.
start_sidekiq
(
%w(foo)
,
:production
)).
to
eq
(
thread
)
# Upon success Process.wait just returns the PID.
expect
(
thread
.
value
).
to
be_a_kind_of
(
Numeric
)
end
end
describe
'.all_alive?'
do
it
'returns true if all
thread
s are alive'
do
threads
=
[
double
(
:thread
,
pid:
1
)
]
it
'returns true if all
processe
s are alive'
do
processes
=
[
1
]
allow
(
described_class
).
to
receive
(
:signal
).
with
(
1
,
0
).
and_return
(
true
)
expect
(
described_class
.
all_alive?
(
thread
s
)).
to
eq
(
true
)
expect
(
described_class
.
all_alive?
(
processe
s
)).
to
eq
(
true
)
end
it
'returns false when a thread was not alive'
do
threads
=
[
double
(
:thread
,
pid:
1
)
]
processes
=
[
1
]
allow
(
described_class
).
to
receive
(
:signal
).
with
(
1
,
0
).
and_return
(
false
)
expect
(
described_class
.
all_alive?
(
thread
s
)).
to
eq
(
false
)
expect
(
described_class
.
all_alive?
(
processe
s
)).
to
eq
(
false
)
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment