tp2 0.4 → 0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d8c8ee2edd1c72a68b21c3ea27dc208c0dbfcbb2a6d78d76abb3ec11f115977
4
- data.tar.gz: 5fb43258443827cf5fa44fc1ddd4960740d8694d5469fac70875c46c54558c15
3
+ metadata.gz: a9c8c52c6ec2e5db6393b54f0ccf96010c9c626984ea943075f1675a078e9eae
4
+ data.tar.gz: 80cf94801b882350e72d50b21e9e004c544d239e3a05e04e99db4543e88deb73
5
5
  SHA512:
6
- metadata.gz: e6c54083c10368f84bd23a0bfd235f01aa74690f7d02667a54c539921e9dc601e7f513858d3a85eee17229d4f4f12a6482d219feb1c1820cd2622c7e70e0dfa9
7
- data.tar.gz: 134a0b072495b5d23f02d1d19e86db66f4f78ffea81ce1e20b48660d77c61966bf83e4876f4870b33f8d63102274d3f3e3555e3166d02cfcaa0086aacdff2520
6
+ metadata.gz: 48484025b54dc3a7ea959c795ed6575d62eae1165f97ed5171343616af84da1fce9cc2e818f7e3fb540dab146b6f0bd8e1a076fba6050e03cb78cfd479615449
7
+ data.tar.gz: a3a65e353b9a5f4c1d4d3af7a4a6977f77ed7c38a1c10eb85c4a4afbbc6cc4a4c8e244be482c66b9e1ce6c61b52ffd0755959e3dff545d87b310011598baec9a
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Version 0.5 2025-05-05
2
+
3
+ - Implement graceful shutdown
4
+
5
+ # Version 0.4 2025-05-02
6
+
7
+ - Add adapter and server tests
8
+ - Remove http/parser dependency, use regexs to parse HTTP requests
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tp2 (0.4)
4
+ tp2 (0.5)
5
5
  qeweney (= 0.21)
6
- uringmachine (= 0.7)
6
+ uringmachine (= 0.8)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
@@ -36,7 +36,7 @@ GEM
36
36
  simplecov_json_formatter (~> 0.1)
37
37
  simplecov-html (0.13.1)
38
38
  simplecov_json_formatter (0.1.4)
39
- uringmachine (0.7)
39
+ uringmachine (0.8)
40
40
  yard (0.9.37)
41
41
 
42
42
  PLATFORMS
data/examples/simple.rb CHANGED
@@ -16,12 +16,19 @@ machine = UM.new
16
16
  server = TP2::Server.new(machine, '0.0.0.0', 1234, &app)
17
17
  puts "Listening on port 1234..."
18
18
 
19
- machine.spin { server.run }
19
+ server_fiber = machine.spin { server.run }
20
20
 
21
- main = Fiber.current
22
- trap('SIGINT') { machine.schedule(main, nil) }
21
+ sig_queue = UM::Queue.new
22
+ trap('SIGINT') { machine.push(sig_queue, :SIGINT) }
23
23
 
24
24
  puts "Running... (pid: #{Process.pid})"
25
25
  STDOUT.flush
26
- machine.yield # wait for termination
26
+
27
+ # wait for signal
28
+ sig = machine.shift(sig_queue)
29
+
30
+ puts "Got signal (#{sig}), shutting down gracefully..."
31
+ machine.schedule(server_fiber, UM::Terminate.new)
32
+ machine.join(server_fiber)
33
+
27
34
  puts
@@ -20,8 +20,10 @@ module TP2
20
20
  persist = serve_request
21
21
  break if !persist
22
22
  end
23
+ rescue UM::Terminate
24
+ # do nothing
23
25
  rescue => e
24
- puts '*' * 40
26
+ puts '!' * 40
25
27
  p e
26
28
  puts e.backtrace.join("\n")
27
29
  exit!
data/lib/tp2/server.rb CHANGED
@@ -5,6 +5,9 @@ require 'tp2/request_extensions'
5
5
 
6
6
  module TP2
7
7
  class Server
8
+ PENDING_REQUESTS_GRACE_PERIOD = 0.1
9
+ PENDING_REQUESTS_TIMEOUT_PERIOD = 5
10
+
8
11
  def initialize(machine, hostname, port, &app)
9
12
  @machine = machine
10
13
  @hostname = hostname
@@ -12,21 +15,61 @@ module TP2
12
15
  @app = app
13
16
  end
14
17
 
18
+ def run
19
+ setup
20
+ accept_incoming
21
+ rescue UM::Terminate
22
+ graceful_shutdown
23
+ end
24
+
25
+ private
26
+
15
27
  def setup
16
28
  @server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
17
29
  @machine.setsockopt(@server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
18
30
  @machine.bind(@server_fd, @hostname, @port)
19
31
  @machine.listen(@server_fd, UM::SOMAXCONN)
20
32
 
33
+ # map fibers
34
+ @fiber_map = {}
35
+
21
36
  # puts "Listening on #{@hostname}:#{@port}"
22
37
  end
23
38
 
24
- def run
25
- setup
39
+ def accept_incoming
26
40
  @machine.accept_each(@server_fd) do |fd|
27
41
  conn = HTTP1Adapter.new(@machine, fd, &@app)
28
- @machine.spin(conn) { it.run }
42
+ f = @machine.spin(conn) do
43
+ it.run
44
+ ensure
45
+ @fiber_map.delete(f)
46
+ end
47
+ @fiber_map[f] = true
48
+ end
49
+ end
50
+
51
+ def graceful_shutdown
52
+ # stop listening
53
+ @machine.close(@server_fd)
54
+
55
+ return if @fiber_map.empty?
56
+
57
+ # sleep for a bit, let requests finish
58
+ @machine.sleep(PENDING_REQUESTS_GRACE_PERIOD)
59
+ return if @fiber_map.empty?
60
+
61
+ # terminate pending fibers
62
+ pending = @fiber_map.keys
63
+ signal = UM::Terminate.new
64
+ pending.each { @machine.schedule(it, signal) }
65
+
66
+ @machine.timeout(PENDING_REQUESTS_TIMEOUT_PERIOD, UM::Terminate) do
67
+ @machine.join(*@fiber_map.keys)
68
+ rescue UM::Terminate
69
+ # timeout on waiting for adapters to finish running, do nothing
29
70
  end
71
+ ensure
72
+ @machine.close(@server_fd)
30
73
  end
31
74
  end
32
75
  end
data/lib/tp2/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module TP2
2
- VERSION = '0.4'
2
+ VERSION = '0.5'
3
3
  end
data/test/test_server.rb CHANGED
@@ -85,6 +85,26 @@ class ServerTest < Minitest::Test
85
85
  assert_equal(expected, response)
86
86
  end
87
87
 
88
+ def test_graceful_shutdown
89
+ @app = ->(req) do
90
+ @machine.sleep(1)
91
+ req.respond('Hello, world!', {})
92
+ rescue UM::Terminate
93
+ req.respond('Terminated!', {})
94
+ raise
95
+ end
96
+
97
+ write_http_request "GET /foo HTTP/1.1\r\nServer: foo.com\r\n\r\nSCHMET /bar HTTP/1.1\r\n\r\n"
98
+
99
+ @machine.sleep(0.01)
100
+ @machine.schedule(@f_server, UM::Terminate.new)
101
+ @machine.snooze
102
+
103
+ response = read_client_side
104
+ expected = "HTTP/1.1 200\r\nContent-Length: 11\r\n\r\nTerminated!"
105
+ assert_equal(expected, response)
106
+ end
107
+
88
108
  def test_pipelined_requests_with_body
89
109
  skip
90
110
 
data/tp2.gemspec CHANGED
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ['lib']
20
20
  s.required_ruby_version = '>= 3.4'
21
21
 
22
- s.add_dependency 'uringmachine', '0.7'
22
+ s.add_dependency 'uringmachine', '0.8'
23
23
  s.add_dependency 'qeweney', '0.21'
24
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tp2
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: '0.7'
18
+ version: '0.8'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: '0.7'
25
+ version: '0.8'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: qeweney
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -44,6 +44,7 @@ extra_rdoc_files:
44
44
  - README.md
45
45
  files:
46
46
  - ".gitignore"
47
+ - CHANGELOG.md
47
48
  - Gemfile
48
49
  - Gemfile.lock
49
50
  - README.md