File tree 5 files changed +216
-0
lines changed
5 files changed +216
-0
lines changed Original file line number Diff line number Diff line change
1
+ #!/usr/bin/env falcon --verbose serve -c
2
+ # frozen_string_literal: true
3
+
4
+ def limited_semaphore_token ( request )
5
+ if request . respond_to? ( :connection )
6
+ io = request . connection . stream . io
7
+
8
+ if io . respond_to? ( :token )
9
+ return io . token
10
+ end
11
+ end
12
+
13
+ return nil
14
+ end
15
+
16
+ run do |env |
17
+ # This is not part of the rack specification, but is available when running under Falcon.
18
+ request = env [ "protocol.http.request" ]
19
+
20
+ # Simulate a leaked IO object:
21
+ # leak_io = request.connection.stream.io.dup
22
+
23
+ # There is no guarantee that there is a connection or that the connection has a token:
24
+ token = limited_semaphore_token ( request )
25
+
26
+ if env [ "PATH_INFO" ] == "/fast"
27
+ if token
28
+ # Keeping the connection alive here is problematic because if the next request is slow, it will "block the server" since we have relinquished the token already.
29
+ token . release
30
+ request . connection . persistent = false
31
+ end
32
+
33
+ # Simulated "fast / non-blocking" request:
34
+ sleep ( 0.01 )
35
+ elsif env [ "PATH_INFO" ] == "/slow"
36
+ # Simulated "slow / blocking" request:
37
+ sleep ( 0.1 )
38
+ end
39
+
40
+ [ 200 , { } , [ "Hello World" ] ]
41
+ end
Original file line number Diff line number Diff line change
1
+ #!/usr/bin/env falcon-host
2
+ # frozen_string_literal: true
3
+
4
+ # Released under the MIT License.
5
+ # Copyright, 2019-2024, by Samuel Williams.
6
+
7
+ require "falcon/environment/rack"
8
+ require_relative "../limited/limited"
9
+
10
+ service "limited.localhost" do
11
+ include Falcon ::Environment ::Rack
12
+
13
+ scheme "http"
14
+ protocol { Async ::HTTP ::Protocol ::HTTP1 . new (
15
+ persistent : false ,
16
+ ) }
17
+
18
+ # Extend the endpoint options to include the (connection) limited wrapper.
19
+ endpoint_options do
20
+ super ( ) . merge (
21
+ protocol : protocol ,
22
+ wrapper : Limited ::Wrapper . new
23
+ )
24
+ end
25
+
26
+ count 1
27
+
28
+ url "http://localhost:8080"
29
+
30
+ endpoint do
31
+ ::Async ::HTTP ::Endpoint . parse ( url ) . with ( **endpoint_options )
32
+ end
33
+ end
Original file line number Diff line number Diff line change
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ falcon (0.51.1)
5
+ async
6
+ async-container (~> 0.20)
7
+ async-container-supervisor (~> 0.5.0)
8
+ async-http (~> 0.75)
9
+ async-http-cache (~> 0.4)
10
+ async-service (~> 0.10)
11
+ bundler
12
+ localhost (~> 1.1)
13
+ openssl (~> 3.0)
14
+ protocol-http (~> 0.31)
15
+ protocol-rack (~> 0.7)
16
+ samovar (~> 2.3)
17
+
18
+ GEM
19
+ remote: https://rubygems.org/
20
+ specs:
21
+ async (2.23.1)
22
+ console (~> 1.29)
23
+ fiber-annotation
24
+ io-event (~> 1.9)
25
+ metrics (~> 0.12)
26
+ traces (~> 0.15)
27
+ async-container (0.24.0)
28
+ async (~> 2.22)
29
+ async-container-supervisor (0.5.1)
30
+ async-container (~> 0.22)
31
+ async-service
32
+ io-endpoint
33
+ memory-leak (~> 0.5)
34
+ async-http (0.88.0)
35
+ async (>= 2.10.2)
36
+ async-pool (~> 0.9)
37
+ io-endpoint (~> 0.14)
38
+ io-stream (~> 0.6)
39
+ metrics (~> 0.12)
40
+ protocol-http (~> 0.49)
41
+ protocol-http1 (~> 0.30)
42
+ protocol-http2 (~> 0.22)
43
+ traces (~> 0.10)
44
+ async-http-cache (0.4.5)
45
+ async-http (~> 0.56)
46
+ async-pool (0.10.3)
47
+ async (>= 1.25)
48
+ async-service (0.13.0)
49
+ async
50
+ async-container (~> 0.16)
51
+ console (1.30.2)
52
+ fiber-annotation
53
+ fiber-local (~> 1.1)
54
+ json
55
+ fiber-annotation (0.2.0)
56
+ fiber-local (1.1.0)
57
+ fiber-storage
58
+ fiber-storage (1.0.0)
59
+ io-endpoint (0.15.2)
60
+ io-event (1.10.0)
61
+ io-stream (0.6.1)
62
+ json (2.10.2)
63
+ kgio (2.11.4)
64
+ localhost (1.3.1)
65
+ mapping (1.1.1)
66
+ memory-leak (0.5.2)
67
+ metrics (0.12.2)
68
+ openssl (3.3.0)
69
+ protocol-hpack (1.5.1)
70
+ protocol-http (0.49.0)
71
+ protocol-http1 (0.31.0)
72
+ protocol-http (~> 0.22)
73
+ protocol-http2 (0.22.1)
74
+ protocol-hpack (~> 1.4)
75
+ protocol-http (~> 0.47)
76
+ protocol-rack (0.11.2)
77
+ protocol-http (~> 0.43)
78
+ rack (>= 1.0)
79
+ rack (3.1.12)
80
+ raindrops (0.20.1)
81
+ samovar (2.3.0)
82
+ console (~> 1.0)
83
+ mapping (~> 1.0)
84
+ traces (0.15.2)
85
+ unicorn (6.1.0)
86
+ kgio (~> 2.6)
87
+ raindrops (~> 0.7)
88
+
89
+ PLATFORMS
90
+ arm64-darwin-24
91
+ ruby
92
+
93
+ DEPENDENCIES
94
+ falcon!
95
+ unicorn (~> 6.1)
96
+
97
+ BUNDLED WITH
98
+ 2.6.2
Original file line number Diff line number Diff line change
1
+ source "https://rubygems.org"
2
+
3
+ gem "unicorn" , "~> 6.1"
4
+ gem "falcon" , path : "../../"
Original file line number Diff line number Diff line change
1
+ # Unicorn (Mode)
2
+
3
+ This is a comparison of Unicorn and Falcon running in single-request-per-process / ` connection: close ` .
4
+
5
+ ## Unicorn
6
+
7
+ ``` sh
8
+ > bundle exec unicorn -E production --port 9090
9
+ ```
10
+
11
+ ## Falcon
12
+
13
+ ``` sh
14
+ > bundle exec falcon host falcon.rb
15
+ ```
16
+
17
+ ## Results
18
+
19
+ ```
20
+ samuel@sakura ~/D/i/wrk (main)> ./wrk --verbose -t1 -c1 -d1 http://localhost:8080
21
+ Running 1s test @ http://localhost:8080
22
+ 1 threads and 1 connections
23
+ 6795 requests in 1.10s, 610.49KB read
24
+ Requests/sec: 6170.43
25
+ Transfer/sec: 554.37KB
26
+
27
+ Thread Stats Avg Stdev Min Max +/- Stdev
28
+ Latency: 153.80us 227.98us 94.00us 5.12ms 97.91%
29
+ Req/sec: 6.22k 2.15k 49.00 7.25k 90.91%
30
+ samuel@sakura ~/D/i/wrk (main)> ./wrk --verbose -t1 -c1 -d1 http://localhost:9090
31
+ Running 1s test @ http://localhost:9090
32
+ 1 threads and 1 connections
33
+ 12070 requests in 1.10s, 0.99MB read
34
+ Requests/sec: 10963.92
35
+ Transfer/sec: 0.90MB
36
+
37
+ Thread Stats Avg Stdev Min Max +/- Stdev
38
+ Latency: 190.98us 1.06ms 45.00us 15.56ms 98.39%
39
+ Req/sec: 11.03k 3.48k 712.00 12.68k 90.91%
40
+ ```
You can’t perform that action at this time.
0 commit comments