ost-bin 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/CHANGELOG.md +12 -2
- data/bin/ost +103 -12
- data/lib/ost-bin/version.rb +1 -1
- data/test/bin.rb +109 -39
- metadata +6 -15
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Mzg5YjIyZTAxMTliOTFjYTE4NWI2MGUwNTMxNWU4MjY2ZjExMDU0YQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzI1ZWRhNmE2NDJlOWZkMTZiZjBlZWUwOGU4MjBjMDNiYzY0YmM4NA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MWJhNGNhYzZlNzBhMWI2OTk2OGYwN2U4Y2IzODA4ODM5ZGJhZjcwMWZmNTJh
|
10
|
+
M2E2ZTI2YmZmMjhhN2IxNjA0NzFkMDQ0MmMyNjRkNGY4ZjliODBlMzA2ZDRi
|
11
|
+
OTc5NWM0OWI0M2Q4NDNkOTkyOTliZjYxYzA1ZTBlZWE3NTUyYzg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzQ3MDUxYWQ1YTIzN2QwNjA5NGNlMzMyZTk5NDEzNzc5YTFlZjlhYTE4ZGJk
|
14
|
+
YmJlMWMyYTM4NjkzMmViM2NlNTkzNGQwYTk0M2M2MWFlMWVjNWJiZWY2MTYy
|
15
|
+
OWY0NmQ4OGVlNGExMTMwY2ViMjhjMDI4ZDM3YjY1ZDk3NzhmOWY=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
-
0.0
|
1
|
+
# 0.1.0 - 2014-05-26
|
2
2
|
|
3
|
-
*
|
3
|
+
* Moved to a threaded model.
|
4
|
+
|
5
|
+
* Added `Ostfile` to specify which workers you want to run.
|
6
|
+
|
7
|
+
* New `-p` switch to specify the path where the PID file should be stored.
|
8
|
+
|
9
|
+
* `ost(1)` now accepts `start` and `stop` commands.
|
10
|
+
|
11
|
+
# 0.0.3 - 2012-07-05
|
12
|
+
|
13
|
+
* Fixed graceful handling of `SIGTERM`.
|
data/bin/ost
CHANGED
@@ -11,28 +11,119 @@ end
|
|
11
11
|
trap(:INT, &stop)
|
12
12
|
trap(:TERM, &stop)
|
13
13
|
|
14
|
+
usage = <<-EOS
|
15
|
+
Usage:
|
16
|
+
|
17
|
+
ost start [-r <require>] [-d] [-p <pid-path>]
|
18
|
+
ost stop [-p <pid-path>]
|
19
|
+
|
20
|
+
EOS
|
21
|
+
|
14
22
|
require "clap"
|
15
23
|
require "ost"
|
16
24
|
|
17
|
-
opts = {
|
25
|
+
opts = {
|
26
|
+
requires: []
|
27
|
+
}
|
18
28
|
|
19
|
-
|
29
|
+
command, _ = Clap.run ARGV,
|
20
30
|
"-d" => -> {
|
21
31
|
opts[:daemonize] = true
|
32
|
+
},
|
33
|
+
"-p" => -> path {
|
34
|
+
opts[:pid_path] = path
|
35
|
+
},
|
36
|
+
"-s" => -> size {
|
37
|
+
opts[:pool_size] = Integer(size)
|
38
|
+
},
|
39
|
+
"-r" => -> file {
|
40
|
+
opts[:requires] << file
|
41
|
+
},
|
42
|
+
"-v" => -> {
|
43
|
+
require_relative "../lib/ost-bin/version"
|
44
|
+
|
45
|
+
puts Ost::Bin::VERSION
|
46
|
+
|
47
|
+
exit 0
|
48
|
+
},
|
49
|
+
"-h" => -> {
|
50
|
+
puts(usage)
|
51
|
+
exit 0
|
22
52
|
}
|
23
53
|
|
24
|
-
|
25
|
-
worker_path = File.expand_path("workers/#{worker}")
|
54
|
+
opts[:pid_path] = File.expand_path("ost.pid") unless opts.include?(:pid_path)
|
26
55
|
|
27
|
-
|
56
|
+
opts[:requires].each do |file|
|
57
|
+
require(file)
|
58
|
+
end
|
28
59
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
60
|
+
module Ost
|
61
|
+
def self.run(worker)
|
62
|
+
workers[worker] = worker.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.workers
|
66
|
+
@workers ||= {}
|
35
67
|
end
|
36
68
|
end
|
37
69
|
|
38
|
-
|
70
|
+
case command
|
71
|
+
when "start"
|
72
|
+
if opts[:daemonize]
|
73
|
+
Process.daemon(true)
|
74
|
+
|
75
|
+
File.open(opts[:pid_path], File::RDWR|File::EXCL|File::CREAT, 0600) do |io|
|
76
|
+
io.write(Process.pid)
|
77
|
+
end
|
78
|
+
|
79
|
+
at_exit do
|
80
|
+
File.delete(opts[:pid_path]) if File.exists?(opts[:pid_path])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
load "./Ostfile"
|
85
|
+
|
86
|
+
opts[:pool_size] = Ost.workers.size unless opts.include?(:pool_size)
|
87
|
+
|
88
|
+
threads_per_worker = opts[:pool_size] / Ost.workers.size
|
89
|
+
|
90
|
+
if threads_per_worker == 0
|
91
|
+
abort("Not enough threads for your workers (found #{Ost.workers.size} workers).")
|
92
|
+
end
|
93
|
+
|
94
|
+
pool = Ost.workers.each_with_object([]) do |(queue, handler), accum|
|
95
|
+
accum.concat(Array.new(threads_per_worker) do
|
96
|
+
Thread.new(queue, handler) do |q, h|
|
97
|
+
queue = Ost[q]
|
98
|
+
|
99
|
+
queue.each do |item|
|
100
|
+
handler.call(item)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end)
|
104
|
+
end
|
105
|
+
|
106
|
+
pool.each(&:join)
|
107
|
+
|
108
|
+
when "stop"
|
109
|
+
pid = Integer(File.read(opts[:pid_path]).chomp)
|
110
|
+
|
111
|
+
running = true
|
112
|
+
|
113
|
+
Process.kill(:TERM, pid)
|
114
|
+
|
115
|
+
while running
|
116
|
+
begin
|
117
|
+
Process.kill(0, pid)
|
118
|
+
running = true
|
119
|
+
rescue Errno::ESRCH
|
120
|
+
running = false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
else
|
125
|
+
$stderr.puts("Unkown command #{command.inspect}.")
|
126
|
+
$stderr.puts(usage)
|
127
|
+
|
128
|
+
exit 2
|
129
|
+
end
|
data/lib/ost-bin/version.rb
CHANGED
data/test/bin.rb
CHANGED
@@ -1,65 +1,88 @@
|
|
1
1
|
require "cutest"
|
2
2
|
require "redis"
|
3
|
+
require "timeout"
|
3
4
|
|
4
5
|
at_exit {
|
5
6
|
Process.waitall
|
6
7
|
}
|
7
8
|
|
8
9
|
def wait_for_pid(pid)
|
9
|
-
running
|
10
|
+
wait_for { !running?(pid) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def wait_for_child(pid)
|
14
|
+
Timeout.timeout(5) do
|
15
|
+
Process.wait(pid)
|
16
|
+
end
|
17
|
+
end
|
10
18
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
running = false
|
19
|
+
def wait_for
|
20
|
+
Timeout.timeout(5) do
|
21
|
+
until value = yield
|
22
|
+
sleep 0.1
|
16
23
|
end
|
24
|
+
|
25
|
+
return value
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
29
|
+
def running?(pid)
|
30
|
+
begin
|
31
|
+
Process.kill(0, pid)
|
32
|
+
true
|
33
|
+
rescue Errno::ESRCH
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_pid_file(path)
|
39
|
+
wait_for { File.exist?(path) && File.size(path) > 0 }
|
40
|
+
|
41
|
+
Integer(File.read(path))
|
42
|
+
end
|
43
|
+
|
20
44
|
def root(path)
|
21
45
|
File.expand_path("../#{path}", File.dirname(__FILE__))
|
22
46
|
end
|
23
47
|
|
24
48
|
redis = Redis.connect
|
25
49
|
|
26
|
-
|
27
|
-
|
50
|
+
prepare do
|
51
|
+
redis.flushdb
|
52
|
+
Dir["test/workers/**/*.pid"].each { |file| File.delete(file) }
|
53
|
+
end
|
54
|
+
|
55
|
+
test "start" do
|
28
56
|
pid = nil
|
29
57
|
|
30
58
|
begin
|
31
59
|
redis.flushdb
|
32
60
|
|
33
|
-
pid = spawn("#{root("bin/ost")}
|
61
|
+
pid = spawn("#{root("bin/ost")} start", chdir: "test/workers/echo")
|
34
62
|
|
35
|
-
redis.rpush("ost:
|
63
|
+
redis.rpush("ost:Echo", 2)
|
36
64
|
|
37
|
-
|
65
|
+
value = wait_for { redis.get("Echo:result") }
|
66
|
+
|
67
|
+
assert_equal "2", value
|
38
68
|
ensure
|
39
69
|
Process.kill(:INT, pid) if pid
|
40
70
|
end
|
41
71
|
end
|
42
72
|
|
43
73
|
test "daemonizes" do
|
44
|
-
r, w = IO.pipe
|
45
74
|
pid, detached_pid = nil
|
46
75
|
|
47
|
-
|
76
|
+
pid_path = "./test/workers/echo/ost.pid"
|
48
77
|
|
49
78
|
begin
|
50
|
-
pid = spawn("#{root("bin/ost")} -d
|
51
|
-
|
52
|
-
sleep 1
|
53
|
-
|
54
|
-
state = `ps -p #{pid} -o state`.lines.to_a.last[/(\w+)/, 1]
|
79
|
+
pid = spawn("#{root("bin/ost")} -d start", chdir: "test/workers/echo")
|
55
80
|
|
56
|
-
|
81
|
+
assert wait_for {
|
82
|
+
`ps -p #{pid} -o state`.lines.to_a.last[/(\w+)/, 1] == "Z"
|
83
|
+
}
|
57
84
|
|
58
|
-
|
59
|
-
|
60
|
-
assert File.exist?(pid_path)
|
61
|
-
|
62
|
-
detached_pid = File.read(pid_path).to_i
|
85
|
+
detached_pid = read_pid_file(pid_path)
|
63
86
|
|
64
87
|
ppid = `ps -p #{detached_pid} -o ppid`.lines.to_a.last[/(\d+)/, 1]
|
65
88
|
|
@@ -75,30 +98,77 @@ test "daemonizes" do
|
|
75
98
|
end
|
76
99
|
|
77
100
|
test "gracefully handles TERM signals" do
|
78
|
-
|
79
|
-
pid, detached_pid = nil
|
101
|
+
redis.rpush("ost:Slow", 3)
|
80
102
|
|
81
|
-
|
103
|
+
begin
|
104
|
+
spawn("#{root("bin/ost")} -d start", chdir: "test/workers/slow")
|
82
105
|
|
83
|
-
|
106
|
+
pid = read_pid_file("./test/workers/slow/ost.pid")
|
84
107
|
|
85
|
-
|
86
|
-
|
108
|
+
assert wait_for { redis.llen("ost:Slow") == 0 }
|
109
|
+
ensure
|
110
|
+
Process.kill(:TERM, pid)
|
111
|
+
end
|
87
112
|
|
88
|
-
|
113
|
+
wait_for_pid(pid)
|
89
114
|
|
90
|
-
|
91
|
-
|
92
|
-
end
|
115
|
+
assert_equal "3", redis.get("slow")
|
116
|
+
end
|
93
117
|
|
94
|
-
|
118
|
+
test "stop waits for workers to be done" do
|
119
|
+
spawn("#{root("bin/ost")} start -d", chdir: "test/workers/slow")
|
95
120
|
|
96
|
-
|
121
|
+
pid = read_pid_file("./test/workers/slow/ost.pid")
|
122
|
+
|
123
|
+
stopper = spawn("#{root("bin/ost")} stop", chdir: "test/workers/slow")
|
124
|
+
|
125
|
+
# Let the stop command start.
|
126
|
+
wait_for { running?(stopper) }
|
127
|
+
|
128
|
+
# Let the stop command end.
|
129
|
+
wait_for_child(stopper)
|
130
|
+
|
131
|
+
# Immediately after the stop command exits,
|
132
|
+
# ost shouldn't be running and the pid file
|
133
|
+
# should be gone.
|
134
|
+
|
135
|
+
assert !running?(pid)
|
136
|
+
assert !File.exist?("./test/workers/slow/ost.pid")
|
137
|
+
end
|
138
|
+
|
139
|
+
test "use a specific path for the pid file" do
|
140
|
+
pid = nil
|
141
|
+
pid_path = "./test/workers/echo/foo.pid"
|
142
|
+
|
143
|
+
begin
|
144
|
+
spawn("#{root("bin/ost")} -d start -p foo.pid", chdir: "test/workers/echo")
|
145
|
+
|
146
|
+
pid = read_pid_file(pid_path)
|
147
|
+
|
148
|
+
assert pid
|
97
149
|
ensure
|
98
|
-
Process.kill(:INT, pid)
|
150
|
+
Process.kill(:INT, pid) if pid
|
99
151
|
end
|
100
152
|
|
101
|
-
wait_for_pid(
|
153
|
+
wait_for_pid(pid)
|
102
154
|
|
103
|
-
|
155
|
+
assert !File.exist?(pid_path)
|
156
|
+
end
|
157
|
+
|
158
|
+
test "load Ostfile" do
|
159
|
+
pid = nil
|
160
|
+
|
161
|
+
begin
|
162
|
+
redis.flushdb
|
163
|
+
|
164
|
+
pid = spawn("#{root("bin/ost")} start", chdir: "test/workers/echo")
|
165
|
+
|
166
|
+
redis.rpush("ost:Echo", 2)
|
167
|
+
|
168
|
+
value = wait_for { redis.get("Echo:result") }
|
169
|
+
|
170
|
+
assert_equal "2", value
|
171
|
+
ensure
|
172
|
+
Process.kill(:INT, pid) if pid
|
173
|
+
end
|
104
174
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ost-bin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Damian Janowski
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-05-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: ost
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: clap
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: cutest
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -71,30 +64,28 @@ files:
|
|
71
64
|
- CHANGELOG.md
|
72
65
|
- lib/ost-bin/version.rb
|
73
66
|
- test/bin.rb
|
74
|
-
-
|
75
|
-
YmluL29zdA==
|
67
|
+
- bin/ost
|
76
68
|
homepage: https://github.com/djanowski/ost-bin
|
77
69
|
licenses: []
|
70
|
+
metadata: {}
|
78
71
|
post_install_message:
|
79
72
|
rdoc_options: []
|
80
73
|
require_paths:
|
81
74
|
- lib
|
82
75
|
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
-
none: false
|
84
76
|
requirements:
|
85
77
|
- - ! '>='
|
86
78
|
- !ruby/object:Gem::Version
|
87
79
|
version: '0'
|
88
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
81
|
requirements:
|
91
82
|
- - ! '>='
|
92
83
|
- !ruby/object:Gem::Version
|
93
84
|
version: '0'
|
94
85
|
requirements: []
|
95
86
|
rubyforge_project:
|
96
|
-
rubygems_version:
|
87
|
+
rubygems_version: 2.0.0
|
97
88
|
signing_key:
|
98
|
-
specification_version:
|
89
|
+
specification_version: 4
|
99
90
|
summary: ost(1)
|
100
91
|
test_files: []
|