jaws 0.5.1 → 0.6.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/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/jaws/server.rb +71 -18
- metadata +9 -9
data/Rakefile
CHANGED
@@ -11,8 +11,8 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/stormbrew/jaws"
|
12
12
|
gem.authors = ["Graham Batty"]
|
13
13
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
-
gem.add_dependency "http_parser", "
|
15
|
-
gem.add_dependency "rack", ">= 1.
|
14
|
+
gem.add_dependency "http_parser", "= 0.1.3"
|
15
|
+
gem.add_dependency "rack", ">= 1.0.0"
|
16
16
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
17
|
end
|
18
18
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/jaws/server.rb
CHANGED
@@ -11,6 +11,7 @@ module Jaws
|
|
11
11
|
name.gsub(%r{(^|_)([a-z])}) { $2.upcase }
|
12
12
|
end
|
13
13
|
|
14
|
+
class GracefulExit < RuntimeError; end
|
14
15
|
class Server
|
15
16
|
DefaultOptions = {
|
16
17
|
:Host => '0.0.0.0',
|
@@ -75,9 +76,10 @@ module Jaws
|
|
75
76
|
# an object that responds to accept() by returning an open connection to a
|
76
77
|
# client. It also has to respond to synchronize and yield to the block
|
77
78
|
# given to that method and be thread safe in that block. It must also
|
78
|
-
# respond to close() by
|
79
|
-
#
|
80
|
-
#
|
79
|
+
# respond to close() by refusing to accept any further connections and
|
80
|
+
# returning true from closed?() thereafter. The accept() call may be interrupted
|
81
|
+
# by a GracefulExit error, it should not block or do anything special with this
|
82
|
+
# error.
|
81
83
|
def create_listener(options)
|
82
84
|
l = TCPServer.new(@host, @port)
|
83
85
|
# let 10 requests back up for each request we can handle concurrently.
|
@@ -249,16 +251,19 @@ module Jaws
|
|
249
251
|
# the connection closes.
|
250
252
|
def process_client(app)
|
251
253
|
loop do
|
254
|
+
client = nil
|
252
255
|
begin
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
256
|
+
make_interruptable do
|
257
|
+
client = @listener.synchronize do
|
258
|
+
begin
|
259
|
+
@listener && @listener.accept()
|
260
|
+
rescue => e
|
261
|
+
return # this means we've been turned off, so exit the loop.
|
262
|
+
end
|
263
|
+
end
|
264
|
+
if (!client)
|
265
|
+
return # nil return means we're quitting, exit loop.
|
258
266
|
end
|
259
|
-
end
|
260
|
-
if (!client)
|
261
|
-
return # nil return means we're quitting, exit loop.
|
262
267
|
end
|
263
268
|
|
264
269
|
req = Http::Parser.new()
|
@@ -285,8 +290,10 @@ module Jaws
|
|
285
290
|
client.close_write
|
286
291
|
end
|
287
292
|
end
|
288
|
-
|
293
|
+
rescue Errno::EPIPE
|
289
294
|
# do nothing, just let the connection close.
|
295
|
+
rescue SystemExit, GracefulExit
|
296
|
+
raise # pass it on.
|
290
297
|
rescue Object => e
|
291
298
|
$stderr.puts("Unhandled error #{e}:")
|
292
299
|
e.backtrace.each do |line|
|
@@ -299,31 +306,69 @@ module Jaws
|
|
299
306
|
end
|
300
307
|
private :process_client
|
301
308
|
|
309
|
+
# Sets the current thread as interruptable. This happens around
|
310
|
+
# the listen part of the thread. This means the thread is receptive
|
311
|
+
# to t.raise.
|
312
|
+
def make_interruptable
|
313
|
+
begin
|
314
|
+
@interruptable.synchronize do
|
315
|
+
@interruptable << Thread.current
|
316
|
+
end
|
317
|
+
yield
|
318
|
+
ensure
|
319
|
+
@interruptable.synchronize do
|
320
|
+
@interruptable.delete(Thread.current)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
302
325
|
# Runs the application through the configured handler.
|
303
326
|
# Can only be run once at a time. If you try to run it more than
|
304
327
|
# once, the second run will block until the first finishes.
|
305
328
|
def run(app)
|
306
329
|
synchronize do
|
330
|
+
@interruptable = []
|
331
|
+
int_orig = trap "INT" do
|
332
|
+
stop()
|
333
|
+
end
|
334
|
+
term_orig = trap "TERM" do
|
335
|
+
stop()
|
336
|
+
end
|
307
337
|
begin
|
308
338
|
@listener = create_listener(@options)
|
339
|
+
@interruptable.extend Mutex_m
|
309
340
|
if (@max_clients > 1)
|
310
341
|
@master = Thread.current
|
311
342
|
@workers = (0...@max_clients).collect do
|
312
343
|
Thread.new do
|
313
|
-
|
344
|
+
begin
|
345
|
+
process_client(app)
|
346
|
+
rescue GracefulExit, SystemExit => e
|
347
|
+
# let it exit.
|
348
|
+
rescue => e
|
349
|
+
$stderr.puts("Handler thread unexpectedly died with #{e}:", e.backtrace)
|
350
|
+
end
|
314
351
|
end
|
315
352
|
end
|
316
353
|
@workers.each do |worker|
|
317
354
|
worker.join
|
318
355
|
end
|
319
356
|
else
|
320
|
-
|
321
|
-
|
322
|
-
|
357
|
+
begin
|
358
|
+
@master = Thread.current
|
359
|
+
@workers = [Thread.current]
|
360
|
+
process_client(app)
|
361
|
+
rescue GracefulExit, SystemExit => e
|
362
|
+
# let it exit
|
363
|
+
rescue => e
|
364
|
+
$stderr.puts("Handler thread unexpectedly died with #{e}:", e.backtrace)
|
365
|
+
end
|
323
366
|
end
|
324
367
|
ensure
|
368
|
+
trap "INT", int_orig
|
369
|
+
trap "TERM", term_orig
|
325
370
|
@listener.close if (@listener && !@listener.closed?)
|
326
|
-
@listener = @master = @workers = nil
|
371
|
+
@interruptable = @listener = @master = @workers = nil
|
327
372
|
end
|
328
373
|
end
|
329
374
|
end
|
@@ -332,7 +377,15 @@ module Jaws
|
|
332
377
|
# close the connection, the handler threads will exit
|
333
378
|
# the next time they try to load.
|
334
379
|
# TODO: Make it force them to exit after a timeout.
|
335
|
-
|
380
|
+
$stderr.puts("Terminating request threads. To force immediate exit, send sigkill.")
|
381
|
+
@interruptable.synchronize do
|
382
|
+
@listener.close if !@listener.closed?
|
383
|
+
@workers.each do |worker|
|
384
|
+
if (@interruptable.include?(worker))
|
385
|
+
worker.raise GracefulExit, "Exiting"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
336
389
|
end
|
337
390
|
|
338
391
|
def running?
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 6
|
8
|
+
- 0
|
9
|
+
version: 0.6.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Graham Batty
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-19 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -36,13 +36,13 @@ dependencies:
|
|
36
36
|
prerelease: false
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - "="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
segments:
|
42
42
|
- 0
|
43
43
|
- 1
|
44
|
-
-
|
45
|
-
version: 0.1.
|
44
|
+
- 3
|
45
|
+
version: 0.1.3
|
46
46
|
type: :runtime
|
47
47
|
version_requirements: *id002
|
48
48
|
- !ruby/object:Gem::Dependency
|
@@ -54,9 +54,9 @@ dependencies:
|
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
segments:
|
56
56
|
- 1
|
57
|
-
- 1
|
58
57
|
- 0
|
59
|
-
|
58
|
+
- 0
|
59
|
+
version: 1.0.0
|
60
60
|
type: :runtime
|
61
61
|
version_requirements: *id003
|
62
62
|
description: A Ruby web server designed to have a predictable and simple concurrency model, and to be capable of running in a pure-ruby environment.
|