Skip to content

Commit 3983738

Browse files
authored
Adds crystal grip framework (TechEmpower#5643)
* adds grip framework * adds parallel support to the benchmark Co-authored-by: Carlos Donderis <cads@mercari.com>
1 parent a9d4f23 commit 3983738

File tree

7 files changed

+286
-0
lines changed

7 files changed

+286
-0
lines changed

frameworks/Crystal/grip/README.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
This is the [Grip](https://github.com/grip-framework/grip) test of the Framework Benchmarks.
2+
Crystal is a new language that closely resembles Ruby with a goal of removing typed variables and parameters (instead inferencing), whilst maintaining top speed through bindings into C.
3+
4+
Grip is a microframework for building RESTful web applications, with ease and joy.
5+
6+
7+
# Grip Benchmarking Test
8+
9+
### Test Type Implementation Source Code
10+
11+
* [JSON](grip.cr)
12+
* [PLAINTEXT](grip.cr)
13+
* [DB](grip.cr)
14+
* [QUERY](grip.cr)
15+
* [CACHED QUERY](grip.cr)
16+
* [UPDATE](grip.cr)
17+
* [FORTUNES](grip.cr)
18+
19+
## Important Libraries
20+
The tests were run with:
21+
* [Software](https://www.example1.com/)
22+
* [Example](http://www.example2.com/)
23+
24+
## Test URLs
25+
### JSON
26+
27+
http://localhost:8080/json
28+
29+
### PLAINTEXT
30+
31+
http://localhost:8080/plaintext
32+
33+
### DB
34+
35+
http://localhost:8080/db
36+
37+
### QUERY
38+
39+
http://localhost:8080/query?queries=
40+
41+
### CACHED QUERY
42+
43+
http://localhost:8080/cached_query?queries=
44+
45+
### UPDATE
46+
47+
http://localhost:8080/update?queries=
48+
49+
### FORTUNES
50+
51+
http://localhost:8080/fortunes
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"framework": "grip",
3+
"tests": [
4+
{
5+
"default": {
6+
"json_url": "/json",
7+
"db_url": "/db",
8+
"query_url": "/queries?queries=",
9+
"fortune_url": "/fortunes",
10+
"update_url": "/updates?queries=",
11+
"plaintext_url": "/plaintext",
12+
"port": 8080,
13+
"approach": "Realistic",
14+
"classification": "Micro",
15+
"database": "postgres",
16+
"framework": "Grip",
17+
"language": "Crystal",
18+
"flavor": "None",
19+
"orm": "Raw",
20+
"platform": "None",
21+
"webserver": "None",
22+
"os": "Linux",
23+
"database_os": "Linux",
24+
"display_name": "Grip",
25+
"notes": "",
26+
"versus": "None"
27+
}
28+
}
29+
]
30+
}

frameworks/Crystal/grip/grip.cr

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
require "grip"
2+
require "pg"
3+
require "ecr/macros"
4+
5+
APPDB = DB.open(ENV["DATABASE_URL"])
6+
ID_MAXIMUM = 10_000
7+
8+
module Grip
9+
module DSL
10+
module Methods
11+
def html(context, content, status_code = HTTP::Status::OK)
12+
context.response.status_code = status_code.to_i
13+
context.response.headers.merge!({"Content-Type" => "text/html; charset=UTF-8"})
14+
context.response.print(content)
15+
context.response
16+
end
17+
end
18+
end
19+
end
20+
21+
private def random_world
22+
id = rand(1..ID_MAXIMUM)
23+
id, random_number = APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: {Int32, Int32})
24+
{id: id, randomNumber: random_number}
25+
end
26+
27+
private def set_world(world)
28+
APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id])
29+
world
30+
end
31+
32+
private def fortunes
33+
data = Array(NamedTuple(id: Int32, message: String)).new
34+
35+
APPDB.query_each("SELECT id, message FROM Fortune") do |rs|
36+
data.push({id: rs.read(Int32), message: rs.read(String)})
37+
end
38+
39+
data
40+
end
41+
42+
private def sanitized_query_count(request)
43+
queries = request.query_params["queries"]? || "1"
44+
queries = queries.to_i? || 1
45+
queries.clamp(1..500)
46+
end
47+
48+
class Json < Grip::Controller::Http
49+
def get(context)
50+
context.response.headers["Server"] = "Grip"
51+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
52+
json(
53+
context,
54+
{
55+
message: "Hello, World!",
56+
}
57+
)
58+
end
59+
end
60+
61+
class Plaintext < Grip::Controller::Http
62+
def get(context)
63+
context.response.headers["Server"] = "Grip"
64+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
65+
text(
66+
context,
67+
"Hello, World!"
68+
)
69+
end
70+
end
71+
72+
class Db < Grip::Controller::Http
73+
def get(context)
74+
context.response.headers["Server"] = "Grip"
75+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
76+
json(
77+
context,
78+
random_world
79+
)
80+
end
81+
end
82+
83+
class Queries < Grip::Controller::Http
84+
def get(context)
85+
results = (1..sanitized_query_count(context.request)).map do
86+
random_world
87+
end
88+
89+
context.response.headers["Server"] = "Grip"
90+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
91+
json(
92+
context,
93+
results
94+
)
95+
end
96+
end
97+
98+
class Updates < Grip::Controller::Http
99+
def get(context)
100+
updated = (1..sanitized_query_count(context.request)).map do
101+
set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)})
102+
end
103+
context.response.headers["Server"] = "Grip"
104+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
105+
json(
106+
context,
107+
updated
108+
)
109+
end
110+
end
111+
112+
class Fortunes < Grip::Controller::Http
113+
def get(context)
114+
data = fortunes
115+
additional_fortune = {
116+
id: 0,
117+
message: "Additional fortune added at request time.",
118+
}
119+
data.push(additional_fortune)
120+
data.sort_by! { |fortune| fortune[:message] }
121+
122+
context.response.headers["Server"] = "Grip"
123+
context.response.headers["Date"] = HTTP.format_time(Time.utc)
124+
125+
io = IO::Memory.new
126+
ECR.embed "views/fortunes.ecr", io
127+
html(
128+
context,
129+
io.to_s
130+
)
131+
end
132+
end
133+
134+
class Application < Grip::Application
135+
def initialize
136+
get "/json", Json
137+
get "/plaintext", Plaintext
138+
get "/db", Db
139+
get "/queries", Queries
140+
get "/updates", Updates
141+
get "/fortunes", Fortunes
142+
end
143+
end
144+
145+
app = Application.new
146+
app.run(8080) do |config|
147+
server = config.server.not_nil!
148+
server.bind_tcp "0.0.0.0", 8080, reuse_port: true
149+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM crystallang/crystal:0.34.0
2+
3+
WORKDIR /grip
4+
COPY views views
5+
COPY run.sh run.sh
6+
COPY grip.cr grip.cr
7+
COPY shard.yml shard.yml
8+
9+
ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56
10+
ENV GRIP_ENV production
11+
12+
RUN shards install
13+
RUN crystal build --release --no-debug grip.cr
14+
15+
CMD bash run.sh

frameworks/Crystal/grip/run.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
for i in $(seq 1 $(nproc --all)); do
4+
./grip -p 8080 &
5+
done
6+
7+
wait

frameworks/Crystal/grip/shard.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: hoge
2+
version: 0.1.0
3+
4+
dependencies:
5+
grip:
6+
github: grip-framework/grip
7+
pg:
8+
github: will/crystal-pg
9+
version: 0.20.0
10+
targets:
11+
grip:
12+
main: grip.cr
13+
14+
crystal: 0.34.0
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Fortunes</title>
5+
</head>
6+
<body>
7+
<table>
8+
<tr>
9+
<th>id</th>
10+
<th>message</th>
11+
</tr>
12+
<% data.each do |fortune| %>
13+
<tr>
14+
<td><%= fortune[:id] %></td>
15+
<td><%= HTML.escape(fortune[:message]) %></td>
16+
</tr>
17+
<% end %>
18+
</table>
19+
</body>
20+
</html>

0 commit comments

Comments
 (0)