tracks 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/tracks.rb +35 -30
- metadata +6 -6
data/lib/tracks.rb
CHANGED
@@ -169,18 +169,21 @@ class Tracks
|
|
169
169
|
# responding to #call. options should be a hash, with the following optional
|
170
170
|
# keys, as symbols
|
171
171
|
#
|
172
|
-
# [:host]
|
173
|
-
# [:port]
|
174
|
-
# [:read_timeout]
|
175
|
-
#
|
172
|
+
# [:host] the host to listen on, defaults to 0.0.0.0
|
173
|
+
# [:port] the port to listen on, defaults to 9292
|
174
|
+
# [:read_timeout] the maximum amount of time, in seconds, to wait on idle
|
175
|
+
# connections, defaults to 30
|
176
|
+
# [:shutdown_timeout] the maximum amount of time, in seconds, to wait for
|
177
|
+
# in process requests to complete when signalled to shut
|
178
|
+
# down, defaults to 30
|
176
179
|
#
|
177
180
|
def initialize(app, options={})
|
178
181
|
@host = options[:host] || options[:Host] || "0.0.0.0"
|
179
182
|
@port = (options[:port] || options[:Port] || "9292").to_s
|
180
183
|
@read_timeout = options[:read_timeout] || 30
|
184
|
+
@shutdown_timeout = options[:shutdown_timeout] || 30
|
181
185
|
@app = app
|
182
186
|
@shutdown_signal, @signal_shutdown = IO.pipe
|
183
|
-
@threads = ThreadGroup.new
|
184
187
|
end
|
185
188
|
|
186
189
|
# :call-seq: Tracks.run(rack_app[, options]) -> nil
|
@@ -191,36 +194,25 @@ class Tracks
|
|
191
194
|
new(app, options).listen
|
192
195
|
end
|
193
196
|
|
194
|
-
# :call-seq: Tracks.shutdown
|
197
|
+
# :call-seq: Tracks.shutdown -> nil
|
195
198
|
#
|
196
|
-
#
|
197
|
-
# each to gracefully shutdown. See #shutdown for more.
|
199
|
+
# Signal all running Tracks servers to shutdown.
|
198
200
|
#
|
199
|
-
def self.shutdown
|
200
|
-
running.dup.
|
201
|
+
def self.shutdown
|
202
|
+
running.dup.each {|s| s.shutdown} && nil
|
201
203
|
end
|
202
204
|
|
203
|
-
# :call-seq: server.shutdown
|
205
|
+
# :call-seq: server.shutdown -> nil
|
204
206
|
#
|
205
|
-
#
|
206
|
-
# shutdown. Returns true on graceful shutdown, false otherwise.
|
207
|
+
# Signal the server to shut down.
|
207
208
|
#
|
208
|
-
|
209
|
-
#
|
210
|
-
# A return value of false indicates there were threads left running after
|
211
|
-
# wait_time had expired which were forcibly killed. This may leave resources
|
212
|
-
# in an inconsistant state, and it is advised you exit the process in this
|
213
|
-
# case (likely what you were planning anyway).
|
214
|
-
#
|
215
|
-
def shutdown(wait=30)
|
209
|
+
def shutdown
|
216
210
|
@shutdown = true
|
217
211
|
self.class.running.delete(self)
|
218
|
-
@signal_shutdown << "x"
|
219
|
-
wait -= sleep 1 until @threads.list.empty? || wait <= 0
|
220
|
-
@threads.list.each {|thread| thread.kill}.empty?
|
212
|
+
@signal_shutdown << "x" && nil
|
221
213
|
end
|
222
214
|
|
223
|
-
# :call-seq: server.listen([socket_server]) ->
|
215
|
+
# :call-seq: server.listen([socket_server]) -> bool
|
224
216
|
#
|
225
217
|
# Start listening for/accepting connections on socket_server. socket_server
|
226
218
|
# defaults to a TCP server listening on the host and port supplied to ::new.
|
@@ -231,19 +223,27 @@ class Tracks
|
|
231
223
|
# This method will block until #shutdown is called. The socket_server will
|
232
224
|
# be closed when this method returns.
|
233
225
|
#
|
226
|
+
# A return value of false indicates there were threads left running after
|
227
|
+
# shutdown_timeout had expired which were forcibly killed. This may leave
|
228
|
+
# resources in an inconsistant state, and it is advised you exit the process
|
229
|
+
# in this case (likely what you were planning anyway).
|
230
|
+
#
|
234
231
|
def listen(server=TCPServer.new(@host, @port))
|
235
232
|
@shutdown = false
|
236
233
|
server.listen(1024) if server.respond_to?(:listen)
|
237
234
|
@port, @host = server.addr[1,2].map{|e| e.to_s} if server.respond_to?(:addr)
|
238
235
|
servers = [server, @shutdown_signal]
|
236
|
+
threads = ThreadGroup.new
|
239
237
|
self.class.running << self
|
240
238
|
puts "Tracks HTTP server available at #{@host}:#{@port}"
|
241
239
|
while select(servers, nil, nil) && !@shutdown
|
242
|
-
|
240
|
+
threads.add(Thread.new(server.accept) {|sock| on_connection(sock)})
|
243
241
|
end
|
244
|
-
@shutdown_signal.sysread(1) && nil
|
245
|
-
ensure
|
246
242
|
server.close
|
243
|
+
wait = @shutdown_timeout
|
244
|
+
wait -= sleep 1 until threads.list.empty? || wait <= 0
|
245
|
+
@shutdown_signal.sysread(1)
|
246
|
+
threads.list.each {|thread| thread.kill}.empty?
|
247
247
|
end
|
248
248
|
|
249
249
|
# :call-seq: server.on_connection(socket) -> nil
|
@@ -260,10 +260,14 @@ class Tracks
|
|
260
260
|
def on_connection(socket)
|
261
261
|
parser = HTTPTools::Parser.new
|
262
262
|
buffer = ""
|
263
|
-
sockets = [socket]
|
263
|
+
sockets = [socket, @shutdown_signal]
|
264
|
+
idle = false
|
264
265
|
reader = Proc.new do
|
265
266
|
readable, = select(sockets, nil, nil, @read_timeout)
|
266
267
|
return unless readable
|
268
|
+
sockets.delete(@shutdown_signal) if @shutdown
|
269
|
+
return if idle && @shutdown
|
270
|
+
idle = false
|
267
271
|
begin
|
268
272
|
socket.sysread(16384, buffer)
|
269
273
|
parser << buffer
|
@@ -301,11 +305,12 @@ class Tracks
|
|
301
305
|
body.each {|chunk| socket << chunk}
|
302
306
|
body.close if body.respond_to?(:close)
|
303
307
|
|
304
|
-
if keep_alive
|
308
|
+
if keep_alive && !@shutdown
|
305
309
|
reader.call until parser.finished?
|
306
310
|
input.reset
|
307
311
|
remainder = parser.rest.lstrip
|
308
312
|
parser.reset << remainder
|
313
|
+
idle = true
|
309
314
|
else
|
310
315
|
break
|
311
316
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-26 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &70193797609180 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70193797609180
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: http_tools
|
27
|
-
requirement: &
|
27
|
+
requirement: &70193797608700 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: 0.4.1
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70193797608700
|
36
36
|
description: A bare-bones Ruby HTTP server that talks Rack and uses a thread per connection
|
37
37
|
model of concurrency.
|
38
38
|
email: mat@sourcetagsandcodes.com
|