Skip to content

Commit e84f792

Browse files
authored
Merge pull request #64 from roc-lang/init-api
Change platform API to include `init` and `respond`
2 parents 1933b91 + 350989e commit e84f792

36 files changed

Lines changed: 598 additions & 359 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ concurrency:
99

1010
jobs:
1111
build-and-test:
12-
runs-on: [ubuntu-20.04]
12+
runs-on: [ubuntu-22.04]
1313
steps:
1414
- uses: actions/checkout@v3
1515

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ app
2020
.DS_Store
2121
*.a
2222
*.dylib
23+
*.ll
2324

2425
# roc linking files
2526
dynhost

Cargo.lock

Lines changed: 21 additions & 97 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,32 @@ A webserver [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explain
1515
Run this example server with `$ roc helloweb.roc` (on linux, add `--linker=legacy`) and go to `http://localhost:8000` in your browser. You can change the port (8000) and the host (localhost) by setting the environment variables ROC_BASIC_WEBSERVER_PORT and ROC_BASIC_WEBSERVER_HOST.
1616

1717
```roc
18-
app [main] {
19-
pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.6.0/LQS_Avcf8ogi1SqwmnytRD4SMYiZ4UcRCZwmAjj1RNY.tar.gz"
18+
app [Model, server] {
19+
pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.7.0/vUnq0H5KAITUGuzI3av6AHYLS8LnaYI6qzIMsTNHq3M.tar.br"
2020
}
2121
2222
import pf.Stdout
2323
import pf.Task exposing [Task]
2424
import pf.Http exposing [Request, Response]
2525
import pf.Utc
2626
27-
main : Request -> Task Response []
28-
main = \req ->
27+
# Model is produced by `init`.
28+
Model : {}
2929
30-
# Log request date, method and url
31-
date = Utc.now! |> Utc.toIso8601Str
32-
Stdout.line! "$(date) $(Http.methodToStr req.method) $(req.url)"
30+
# With `init` you can set up a database connection once at server startup,
31+
# generate css by running `tailwindcss`,...
32+
# In this case we don't have anything to initialize, so it is just `Task.ok {}`.
3333
34-
Task.ok { status: 200, headers: [], body: Str.toUtf8 "<b>Hello, world!</b>\n" }
34+
server = { init: Task.ok {}, respond }
3535
36+
respond : Request, Model -> Task Response [ServerErr Str]_
37+
respond = \req, _ ->
38+
# Log request datetime, method and url
39+
datetime = Utc.now! |> Utc.toIso8601Str
40+
41+
Stdout.line! "$(datetime) $(Http.methodToStr req.method) $(req.url)"
42+
43+
Task.ok { status: 200, headers: [], body: Str.toUtf8 "<b>Hello, world!</b></br>" }
3644
```
3745

3846

@@ -43,3 +51,25 @@ If you'd like to contribute, check out our [group chat](https://roc.zulipchat.co
4351
## Developing / Building Locally
4452

4553
If you have cloned this repository and want to run the examples without using a packaged release (...tar.br), you will need to build the platform first by running `roc build.roc`. Run examples with `roc examples/hello.roc` (on linux, add `--linker=legacy`).
54+
55+
## Benchmarking
56+
57+
Basic webserver should have decent performance due to being built on top of Rust's [hyper](https://hyper.rs).
58+
That said, it has a few known issues that hurt performance:
59+
1. We do [extra data copying on every request](https://github.com/roc-lang/basic-webserver/issues/23).
60+
2. Until roc has effect interpreters, basic-webserver can only do blocking io for effects. To work around this, every request is spawned in a blocking thread.
61+
3. Until [sqlite improvements](https://github.com/roc-lang/basic-webserver/pull/61) land, we never prepare queries.
62+
63+
That said, running benchmarks and debugging performance is still a great idea. It can help improve both Roc and basic-webserver.
64+
65+
Lots of load generators exist. Generally, it is advised to use one that avoids [coordinated omission](https://www.youtube.com/watch?v=lJ8ydIuPFeU).
66+
A trusted generator that fits this criteria is [wrk2](https://github.com/giltene/wrk2) (sadly doesn't work on Apple Silicon).
67+
68+
If you are benchmarking on a single machine, you can use the `TOKIO_WORKER_THREADS` environment variable to limit parallelism of the webserver.
69+
70+
> Note: When benchmarking, it is best to run the load generator and the webserver on different machines.
71+
72+
When benchmarking on a single 8 core machine with `wrk2`, these commands could be used (simply tune connections `-c` and rate `-R`):
73+
1. Optimized Build: `roc build --optimize my-webserver.roc`
74+
2. Launch server with 4 cores: `TOKIO_WORKER_THREADS=4 ./my-webserver`
75+
3. Generate load with 4 cores: `wrk -t4 -c100 -d30s -R2000 http://127.0.0.1:8000`

ci/all_tests.sh

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,9 @@ find . -type d -name "roc_nightly" -prune -o -type f -name "*.roc" -print | whil
5555
fi
5656
done
5757

58-
# TODO use loop instead
59-
expect ci/expect_scripts/command.exp
60-
expect ci/expect_scripts/dir.exp
61-
expect ci/expect_scripts/echo.exp
62-
expect ci/expect_scripts/env.exp
63-
expect ci/expect_scripts/error-handling.exp
64-
expect ci/expect_scripts/file.exp
65-
expect ci/expect_scripts/hello-web.exp
66-
expect ci/expect_scripts/sleep.exp
67-
expect ci/expect_scripts/result.exp
58+
for script in ci/expect_scripts/*.exp; do
59+
expect "$script"
60+
done
6861

6962
# test building website
7063
$ROC docs platform/main.roc

ci/expect_scripts/command.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ spawn $env(EXAMPLES_DIR)command
1010
expect "Listening on <http://127.0.0.1:8000>\r\n" {
1111
set curlOutput [exec curl -sS localhost:8000]
1212

13-
if {$curlOutput eq "Command succeeded"} {
13+
if {$curlOutput eq "Command succeeded."} {
1414
expect "Z Get /\r\n" {
1515
exit 0
1616
}

ci/expect_scripts/hello-web.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ spawn $env(EXAMPLES_DIR)hello-web
1010
expect "Listening on <http://127.0.0.1:8000>\r\n" {
1111
set curlOutput [exec curl -sS localhost:8000]
1212

13-
if {$curlOutput eq "<b>Hello, world!</b>"} {
13+
if {$curlOutput eq "<b>Hello from server</b></br>"} {
1414
expect "Z Get /\r\n" {
1515
exit 0
1616
}

ci/expect_scripts/init-basic.exp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/expect
2+
3+
# uncomment line below for debugging
4+
# exp_internal 1
5+
6+
set timeout 7
7+
8+
spawn $env(EXAMPLES_DIR)init-basic
9+
10+
expect "Listening on <http://127.0.0.1:8000>\r\n" {
11+
set curlOutput [exec curl -sS localhost:8000]
12+
13+
if {$curlOutput eq "<b>init gave me 🎁</b>"} {
14+
expect "Z Get /\r\n" {
15+
exit 0
16+
}
17+
} else {
18+
puts "Error: curl output was different than expected: $curlOutput"
19+
exit 1
20+
}
21+
}
22+
23+
puts stderr "\nError: output was different than expected."
24+
exit 1

0 commit comments

Comments
 (0)