Skip to content

Commit b774a2d

Browse files
committed
Add comparison with Unicorn.
1 parent 55b8bab commit b774a2d

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

examples/unicorn/config.ru

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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

examples/unicorn/falcon.rb

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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

examples/unicorn/gems.locked

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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

examples/unicorn/gems.rb

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source "https://rubygems.org"
2+
3+
gem "unicorn", "~> 6.1"
4+
gem "falcon", path: "../../"

examples/unicorn/readme.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
```

0 commit comments

Comments
 (0)