📖 docs: main branch
--linker=legacy
is necessary for this package because of this Roc issue.
Basic Web Server for Roc
A webserver platform with a simple interface.
🏎️ basic-webserver uses Rust's high-performance hyper and tokio libraries to execute your Roc function on incoming requests.
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.
app [Model, server] { pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.9.0/taU2jQuBf-wB8EJb0hAkrYLYOGacUU5Y9reiHG45IY4.tar.br" }
import pf.Stdout
import pf.Http exposing [Request, Response]
import pf.Utc
# Model is produced by `init`.
Model : {}
# With `init` you can set up a database connection once at server startup,
# generate css by running `tailwindcss`,...
# In this case we don't have anything to initialize, so it is just `Task.ok {}`.
server = { init: Task.ok {}, respond }
respond : Request, Model -> Task Response [ServerErr Str]_
respond = \req, _ ->
# Log request datetime, method and url
datetime = Utc.now! |> Utc.toIso8601Str
Stdout.line! "$(datetime) $(Http.methodToStr req.method) $(req.url)"
Task.ok { status: 200, headers: [], body: Str.toUtf8 "<b>Hello, web!</b></br>" }
If you'd like to contribute, check out our group chat and let us know what you're thinking, we're friendly!
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
).
Basic webserver should have decent performance due to being built on top of Rust's hyper. That said, it has a few known issues that hurt performance:
- We do extra data copying on every request.
- 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.
- Until sqlite improvements land, we never prepare queries.
That said, running benchmarks and debugging performance is still a great idea. It can help improve both Roc and basic-webserver.
Lots of load generators exist. Generally, it is advised to use one that avoids coordinated omission. A trusted generator that fits this criteria is wrk2 (sadly doesn't work on Apple Silicon).
If you are benchmarking on a single machine, you can use the TOKIO_WORKER_THREADS
environment variable to limit parallelism of the webserver.
Note: When benchmarking, it is best to run the load generator and the webserver on different machines.
When benchmarking on a single 8 core machine with wrk2
, these commands could be used (simply tune connections -c
and rate -R
):
- Optimized Build:
roc build --optimize my-webserver.roc
- Launch server with 4 cores:
TOKIO_WORKER_THREADS=4 ./my-webserver
- Generate load with 4 cores:
wrk -t4 -c100 -d30s -R2000 http://127.0.0.1:8000