sqsrun 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +20 -0
- data/README.rdoc +55 -4
- data/lib/sqsrun/command/sqsrun.rb +76 -8
- data/lib/sqsrun/controller.rb +28 -1
- data/lib/sqsrun/version.rb +1 -1
- data/lib/sqsrun/worker.rb +46 -17
- metadata +6 -4
data/ChangeLog
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
== 2011-07-18 version 0.5.0
|
3
|
+
|
4
|
+
* Added respectable timeout implementation
|
5
|
+
* Added --create command: creates a new queue
|
6
|
+
* Added --delete command: deletes a queue
|
7
|
+
* Added --attr command: updates attributes of a queue
|
8
|
+
* --list command shows attributes of queues
|
9
|
+
|
10
|
+
|
11
|
+
== 2011-07-11 version 0.4.0
|
12
|
+
|
13
|
+
* Splits single bin file into multiple files
|
14
|
+
* Added test codes
|
15
|
+
|
16
|
+
|
17
|
+
== 2011-07-10 version 0.3.0
|
18
|
+
|
19
|
+
* Initial release
|
20
|
+
|
data/README.rdoc
CHANGED
@@ -20,6 +20,9 @@ A Generics Worker Executor Service for Amazon SQS. It polls SQS queue and run co
|
|
20
20
|
-s, --secret-key KEY AWS Secret Access Key
|
21
21
|
-q, --queue NAME SQS queue name
|
22
22
|
-t, --timeout SEC SQS visibility timeout (default: 30)
|
23
|
+
--create Create new queue
|
24
|
+
--delete Delete a queue
|
25
|
+
--attr Key=Value Set attribute
|
23
26
|
--push MESSAGE Push maessage to the queue
|
24
27
|
--list List queues
|
25
28
|
--configure PATH.yaml Write configuration file
|
@@ -27,21 +30,57 @@ A Generics Worker Executor Service for Amazon SQS. It polls SQS queue and run co
|
|
27
30
|
--run SCRIPT.rb Run method named 'run' defined in the script
|
28
31
|
-e, --extend-timeout SEC Threashold time before extending visibility timeout (default: timeout * 3/4)
|
29
32
|
-x, --kill-timeout SEC Threashold time before killing process (default: timeout * 5)
|
33
|
+
-X, --kill-retry SEC Threashold time before retrying killing process (default: 60)
|
30
34
|
-i, --interval SEC Polling interval (default: 1)
|
31
35
|
-d, --daemon PIDFILE Daemonize (default: foreground)
|
32
36
|
-f, --file PATH.yaml Read configuration file
|
33
37
|
|
34
|
-
One of --
|
38
|
+
One of --list, --create, --delete, --attr, --push, --configure, --exec or --run is required. The behavior of the commands is described below:
|
39
|
+
|
40
|
+
|
41
|
+
=== list
|
42
|
+
|
43
|
+
Show list of queues. -k and -s options are required.
|
44
|
+
|
45
|
+
_Example:_
|
46
|
+
|
47
|
+
$ sqsrun -k KEY_ID -s SEC_KEY --list
|
48
|
+
|
49
|
+
|
50
|
+
=== create
|
51
|
+
|
52
|
+
Create new queue. -k, -s and -q options are required.
|
53
|
+
|
54
|
+
_Example:_
|
55
|
+
|
56
|
+
$ sqsrun -k KEY_ID -s SEC_KEY --create -q myqueue
|
57
|
+
|
58
|
+
|
59
|
+
=== delete
|
60
|
+
|
61
|
+
Delete a queue. -k, -s and -q options are required. Note that messages in the queue will be lost.
|
62
|
+
|
63
|
+
_Example:_
|
64
|
+
|
65
|
+
$ sqsrun -k KEY_ID -s SEC_KEY --delete -q myqueue
|
66
|
+
|
67
|
+
|
68
|
+
=== attr
|
69
|
+
|
70
|
+
Set a attribute on a queue. -k, -s and -q options are required.
|
71
|
+
|
72
|
+
_Example:_
|
73
|
+
|
74
|
+
$ sqsrun -k KEY_ID -s SEC_KEY -q myqueue --attr MessageRetentionPeriod=3600
|
35
75
|
|
36
76
|
|
37
77
|
=== push
|
38
78
|
|
39
79
|
Push a message to the queue. -k, -s and -q options are required.
|
40
80
|
|
81
|
+
_Example:_
|
41
82
|
|
42
|
-
|
43
|
-
|
44
|
-
Show list of queues. -k and -s options are required.
|
83
|
+
$ sqsrun -k KEY_ID -s SEC_KEY -q myqueue --push '{"a":"b"}'
|
45
84
|
|
46
85
|
|
47
86
|
=== configure
|
@@ -66,12 +105,15 @@ Execute a command when a message is received. Body of the message is passed to t
|
|
66
105
|
_Example:_
|
67
106
|
|
68
107
|
#!/usr/bin/env ruby
|
108
|
+
|
69
109
|
require 'json'
|
70
110
|
js = JSON.load(STDIN.read)
|
71
111
|
puts "received: #{js.inspect}"
|
72
112
|
|
73
113
|
# $ sqsrun -k AWS_KEY_ID -s AWS_SEC_KEY -q SQS_NAME --exec ./this_file
|
74
114
|
|
115
|
+
When the kill timeout (-x, --klill-timeout) is elapsed, SIGTERM signal will be sent to the child process. The signal will be repeated every few seconds (-X, --kill-retry).
|
116
|
+
|
75
117
|
|
76
118
|
=== run
|
77
119
|
|
@@ -80,10 +122,19 @@ This is same as 'exec' except that this calls a method named 'run' defined in th
|
|
80
122
|
_Example:_
|
81
123
|
|
82
124
|
require 'json'
|
125
|
+
|
83
126
|
def run(msg)
|
84
127
|
js = JSON.load(msg)
|
85
128
|
puts "received: #{js.inspect}"
|
86
129
|
end
|
87
130
|
|
131
|
+
# optionally you can define terminate method
|
132
|
+
# which will be called when kill timeout is elapsed.
|
133
|
+
def terminate
|
134
|
+
end
|
135
|
+
|
88
136
|
# $ sqsrun -k AWS_KEY_ID -s AWS_SEC_KEY -q SQS_NAME --run ./this_file.rb
|
89
137
|
|
138
|
+
|
139
|
+
When the kill timeout (-x, --klill-timeout) is elapsed, terminate() method will be called (if it is defined). It will be repeated every few seconds (-X, --kill-retry).
|
140
|
+
|
@@ -8,11 +8,13 @@ op.banner += " [-- <ARGV-for-exec-or-run>]"
|
|
8
8
|
|
9
9
|
type = nil
|
10
10
|
message = nil
|
11
|
+
attrkv = nil
|
11
12
|
confout = nil
|
12
13
|
|
13
14
|
defaults = {
|
14
15
|
:timeout => 30,
|
15
16
|
:interval => 1,
|
17
|
+
:kill_retry => 60,
|
16
18
|
}
|
17
19
|
|
18
20
|
conf = { }
|
@@ -33,6 +35,20 @@ op.on('-t', '--timeout SEC', 'SQS visibility timeout (default: 30)', Integer) {|
|
|
33
35
|
conf[:timeout] = i
|
34
36
|
}
|
35
37
|
|
38
|
+
op.on('--create', 'Create new queue') {|s|
|
39
|
+
type = :create
|
40
|
+
}
|
41
|
+
|
42
|
+
op.on('--delete', 'Delete a queue') {|s|
|
43
|
+
type = :delete
|
44
|
+
}
|
45
|
+
|
46
|
+
op.on('--attr Key=Value', 'Set attribute') {|s|
|
47
|
+
type = :attr
|
48
|
+
k, v = s.split('=',2)
|
49
|
+
attrkv = [k.to_s, v.to_s]
|
50
|
+
}
|
51
|
+
|
36
52
|
op.on('--push MESSAGE', 'Push maessage to the queue') {|s|
|
37
53
|
type = :push
|
38
54
|
message = s
|
@@ -65,6 +81,10 @@ op.on('-x', '--kill-timeout SEC', 'Threashold time before killing process (defau
|
|
65
81
|
conf[:kill_timeout] = i
|
66
82
|
}
|
67
83
|
|
84
|
+
op.on('-X', '--kill-retry SEC', 'Threashold time before retrying killing process (default: 60)', Integer) {|i|
|
85
|
+
conf[:kill_retry] = i
|
86
|
+
}
|
87
|
+
|
68
88
|
op.on('-i', '--interval SEC', 'Polling interval (default: 1)', Integer) {|i|
|
69
89
|
conf[:interval] = i
|
70
90
|
}
|
@@ -122,7 +142,7 @@ begin
|
|
122
142
|
elsif conf[:exec]
|
123
143
|
type = :exec
|
124
144
|
else
|
125
|
-
raise "--
|
145
|
+
raise "--list, --create, --delete, --attr, --push, --configure, --exec or --run is required"
|
126
146
|
end
|
127
147
|
end
|
128
148
|
|
@@ -142,7 +162,7 @@ begin
|
|
142
162
|
conf[:kill_timeout] = conf[:timeout] * 5
|
143
163
|
end
|
144
164
|
|
145
|
-
if !conf[:queue] && (type
|
165
|
+
if !conf[:queue] && (type != :list && type != :conf)
|
146
166
|
raise "-q, --queue NAME option is required"
|
147
167
|
end
|
148
168
|
|
@@ -168,14 +188,54 @@ end
|
|
168
188
|
|
169
189
|
|
170
190
|
case type
|
191
|
+
when :create
|
192
|
+
con = SQSRun::Controller.new(conf)
|
193
|
+
if con.create
|
194
|
+
puts "Queue #{conf[:queue].to_s.dump} is created."
|
195
|
+
puts "Note that it takes some seconds before the list is updated."
|
196
|
+
else
|
197
|
+
puts "queue #{conf[:queue].to_s.dump} already exists."
|
198
|
+
end
|
199
|
+
|
200
|
+
when :delete
|
201
|
+
con = SQSRun::Controller.new(conf)
|
202
|
+
if con.delete(true)
|
203
|
+
puts "Queue #{conf[:queue].to_s.dump} is deleted."
|
204
|
+
puts "Note that it takes some seconds before the list is updated."
|
205
|
+
else
|
206
|
+
puts "Queue #{conf[:queue].to_s.dump} does not exist."
|
207
|
+
end
|
208
|
+
|
209
|
+
when :attr
|
210
|
+
con = SQSRun::Controller.new(conf)
|
211
|
+
k, v = *attrkv
|
212
|
+
if con.set_attribute(k, v)
|
213
|
+
puts "#{k}=#{v.to_s.dump}"
|
214
|
+
else
|
215
|
+
puts "Queue #{conf[:queue].to_s.dump} does not exist."
|
216
|
+
end
|
217
|
+
|
171
218
|
when :push
|
172
|
-
|
173
|
-
|
219
|
+
con = SQSRun::Controller.new(conf)
|
220
|
+
con.push(message)
|
174
221
|
|
175
222
|
when :list
|
176
|
-
|
177
|
-
|
178
|
-
|
223
|
+
require 'json'
|
224
|
+
format = "%10s %5s %s"
|
225
|
+
con = SQSRun::Controller.new(conf)
|
226
|
+
list = con.list
|
227
|
+
puts format % ['name', 'size', 'attributes']
|
228
|
+
list.each {|queue|
|
229
|
+
begin
|
230
|
+
name = queue.name
|
231
|
+
size = queue.size
|
232
|
+
queue.get_attribute.each_pair {|k,v|
|
233
|
+
puts format % [name, size, "#{k}=#{v.to_s.dump}"]
|
234
|
+
name = ''
|
235
|
+
size = ''
|
236
|
+
}
|
237
|
+
rescue RightAws::AwsError
|
238
|
+
end
|
179
239
|
}
|
180
240
|
|
181
241
|
when :exec, :run
|
@@ -208,10 +268,18 @@ when :exec, :run
|
|
208
268
|
if type == :run
|
209
269
|
load File.expand_path(conf[:run])
|
210
270
|
run_proc = method(:run)
|
271
|
+
if defined? terminate
|
272
|
+
kill_proc = method(:terminate)
|
273
|
+
else
|
274
|
+
kill_proc = Proc.new { }
|
275
|
+
end
|
211
276
|
else
|
212
277
|
run_proc = SQSRun::ExecRunner.new(conf[:exec])
|
278
|
+
kill_proc = run_proc.method(:terminate)
|
213
279
|
end
|
214
280
|
|
215
|
-
worker.
|
281
|
+
worker.init_proc(run_proc, kill_proc)
|
282
|
+
|
283
|
+
worker.run
|
216
284
|
end
|
217
285
|
|
data/lib/sqsrun/controller.rb
CHANGED
@@ -17,9 +17,36 @@ class Controller
|
|
17
17
|
@queue.send_message(body)
|
18
18
|
end
|
19
19
|
|
20
|
+
def create
|
21
|
+
@sqs = RightAws::SqsGen2.new(@key_id, @secret_key)
|
22
|
+
@queue = @sqs.queue(@queue_name, false)
|
23
|
+
if @queue
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
@queue = @sqs.queue(@queue_name, true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(force=false)
|
30
|
+
@sqs = RightAws::SqsGen2.new(@key_id, @secret_key)
|
31
|
+
@queue = @sqs.queue(@queue_name, false)
|
32
|
+
unless @queue
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
@queue.delete(force)
|
36
|
+
end
|
37
|
+
|
20
38
|
def list
|
21
39
|
@sqs = RightAws::SqsGen2.new(@key_id, @secret_key)
|
22
|
-
@sqs.queues
|
40
|
+
@sqs.queues
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_attribute(k, v)
|
44
|
+
@sqs = RightAws::SqsGen2.new(@key_id, @secret_key)
|
45
|
+
@queue = @sqs.queue(@queue_name, false)
|
46
|
+
unless @queue
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
@queue.set_attribute(k, v)
|
23
50
|
end
|
24
51
|
end
|
25
52
|
|
data/lib/sqsrun/version.rb
CHANGED
data/lib/sqsrun/worker.rb
CHANGED
@@ -12,10 +12,11 @@ class Worker
|
|
12
12
|
@visibility_timeout = conf[:timeout]
|
13
13
|
@extend_timeout = conf[:extend_timeout]
|
14
14
|
@kill_timeout = conf[:kill_timeout]
|
15
|
+
@kill_retry = conf[:kill_retry]
|
15
16
|
@interval = conf[:interval]
|
16
17
|
@finished = false
|
17
18
|
|
18
|
-
@extender =
|
19
|
+
@extender = TimerThread.new(@visibility_timeout, @extend_timeout, @kill_timeout, @kill_retry)
|
19
20
|
@sqs = RightAws::SqsGen2.new(@key_id, @secret_key)
|
20
21
|
@queue = @sqs.queue(@queue_name)
|
21
22
|
|
@@ -23,8 +24,12 @@ class Worker
|
|
23
24
|
@cond = ConditionVariable.new
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
+
def init_proc(run_proc, kill_proc)
|
27
28
|
@run_proc = run_proc
|
29
|
+
@extender.init_proc(kill_proc)
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
28
33
|
@extender.start
|
29
34
|
until @finished
|
30
35
|
msg = @queue.receive(@visibility_timeout)
|
@@ -79,15 +84,8 @@ class Worker
|
|
79
84
|
|
80
85
|
success = false
|
81
86
|
begin
|
82
|
-
|
83
|
-
|
84
|
-
thread.value
|
85
|
-
success = true
|
86
|
-
puts "finished id=#{msg.id}"
|
87
|
-
else
|
88
|
-
thread.kill
|
89
|
-
puts "killed id=#{msg.id}"
|
90
|
-
end
|
87
|
+
thread.join
|
88
|
+
success = true
|
91
89
|
rescue
|
92
90
|
puts "failed id=#{msg.id}: #{$!}"
|
93
91
|
$!.backtrace.each {|bt|
|
@@ -104,18 +102,26 @@ class Worker
|
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
107
|
-
class
|
105
|
+
class TimerThread
|
108
106
|
include MonitorMixin
|
109
107
|
|
110
|
-
def initialize(visibility_timeout, extend_timeout)
|
108
|
+
def initialize(visibility_timeout, extend_timeout, kill_timeout, kill_retry)
|
111
109
|
super()
|
112
110
|
@visibility_timeout = visibility_timeout
|
113
111
|
@extend_timeout = extend_timeout
|
112
|
+
@kill_timeout = kill_timeout
|
113
|
+
@kill_retry = kill_retry
|
114
|
+
@kill_time = nil
|
115
|
+
@kill_proc = nil
|
114
116
|
@extend_time = nil
|
115
117
|
@message = nil
|
116
118
|
@finished = false
|
117
119
|
end
|
118
120
|
|
121
|
+
def init_proc(kill_proc)
|
122
|
+
@kill_proc = kill_proc
|
123
|
+
end
|
124
|
+
|
119
125
|
def start
|
120
126
|
@thread = Thread.new(&method(:run))
|
121
127
|
end
|
@@ -126,7 +132,9 @@ class Worker
|
|
126
132
|
|
127
133
|
def set_message(msg)
|
128
134
|
synchronize do
|
129
|
-
|
135
|
+
now = Time.now.to_i
|
136
|
+
@extend_time = now + @extend_timeout
|
137
|
+
@kill_time = now + @kill_timeout
|
130
138
|
@message = msg
|
131
139
|
end
|
132
140
|
end
|
@@ -146,13 +154,16 @@ class Worker
|
|
146
154
|
until @finished
|
147
155
|
sleep 1
|
148
156
|
synchronize do
|
149
|
-
|
157
|
+
if @message
|
158
|
+
now = Time.now.to_i
|
159
|
+
try_kill(now, @message)
|
160
|
+
try_extend(now, @message)
|
161
|
+
end
|
150
162
|
end
|
151
163
|
end
|
152
164
|
end
|
153
165
|
|
154
|
-
def try_extend(msg)
|
155
|
-
now = Time.now.to_i
|
166
|
+
def try_extend(now, msg)
|
156
167
|
if now > @extend_time
|
157
168
|
ntime = msg.visibility + @visibility_timeout
|
158
169
|
puts "extending timeout=#{ntime} id=#{msg.id}"
|
@@ -160,6 +171,16 @@ class Worker
|
|
160
171
|
@extend_time = now + @extend_timeout
|
161
172
|
end
|
162
173
|
end
|
174
|
+
|
175
|
+
def try_kill(now, msg)
|
176
|
+
if now > @kill_time
|
177
|
+
if @kill_proc
|
178
|
+
puts "killing #{msg.id}..."
|
179
|
+
@kill_proc.call rescue nil
|
180
|
+
end
|
181
|
+
@kill_time = now + @kill_retry
|
182
|
+
end
|
183
|
+
end
|
163
184
|
end
|
164
185
|
end
|
165
186
|
|
@@ -168,10 +189,13 @@ class ExecRunner
|
|
168
189
|
def initialize(cmd)
|
169
190
|
@cmd = cmd + ' ' + ARGV.map {|a| Shellwords.escape(a) }.join(' ')
|
170
191
|
@iobuf = ''
|
192
|
+
@pid = nil
|
193
|
+
@next_kill = :TERM
|
171
194
|
end
|
172
195
|
|
173
196
|
def call(message)
|
174
197
|
IO.popen(@cmd, "r+") {|io|
|
198
|
+
@pid = io.pid
|
175
199
|
io.write(message) rescue nil
|
176
200
|
io.close_write
|
177
201
|
begin
|
@@ -186,6 +210,11 @@ class ExecRunner
|
|
186
210
|
raise "Command failed"
|
187
211
|
end
|
188
212
|
end
|
213
|
+
|
214
|
+
def terminate
|
215
|
+
Process.kill(@next_kill, @pid)
|
216
|
+
@next_kill = :KILL
|
217
|
+
end
|
189
218
|
end
|
190
219
|
|
191
220
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqsrun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sadayuki Furuhashi
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-18 00:00:00 +09:00
|
19
19
|
default_executable: sqsrun
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -41,6 +41,7 @@ executables:
|
|
41
41
|
extensions: []
|
42
42
|
|
43
43
|
extra_rdoc_files:
|
44
|
+
- ChangeLog
|
44
45
|
- README.rdoc
|
45
46
|
files:
|
46
47
|
- bin/sqsrun
|
@@ -50,6 +51,7 @@ files:
|
|
50
51
|
- lib/sqsrun/worker.rb
|
51
52
|
- test/exec_test.rb
|
52
53
|
- test/test_helper.rb
|
54
|
+
- ChangeLog
|
53
55
|
- README.rdoc
|
54
56
|
- test/cat.sh
|
55
57
|
- test/fail.sh
|