Contributing to Roadrunner

View Source
  1. Setup
  2. Workflow
  3. License
  4. Reporting a bug
  5. Requesting or implementing a feature
  6. Submitting your changes
    1. Code Style
    2. Committing your changes
    3. Pull requests and branching
    4. Credits

Setup

See .tool-versions for the required Erlang/OTP and rebar3 versions (install via mise or asdf).

git clone https://github.com/arizona-framework/roadrunner.git
cd roadrunner
make compile

Workflow

One command covers day-to-day development:

  • make test (or make precommit, or rebar3 precommit) — run before every commit and before pushing. Formats-check Erlang via erlfmt, compiles, runs xref + hank + dialyzer, runs the eunit + Common Test (incl. PropEr) suites with cover, fails if line coverage drops below 100 %, and builds the docs. CI runs the same command.

make help lists every target. Common ones:

  • make compile / make doc / make fmt
  • make eunit / make ct / make dialyzer / make xref / make hank (individual stages)
  • make bench-quick / make wrk2-quick / make h2spec / make autobahn
  • make clean / make distclean

You can also invoke rebar3 <task> directly (the Makefile is just a thin wrapper over the same targets). See rebar.config for the full alias list.

Diagnostic / conformance scripts under scripts/ (bench.escript, h2spec.sh, autobahn.escript, redbot.escript, wrk2_bench.sh) are run directly; each script's header documents its requirements.

Test surface

PropEr properties via ct_property_test cover the surfaces where input-shape coverage matters: roadrunner_uri (percent round-trip + encode shape), roadrunner_qs (round-trip), roadrunner_cookie (adversarial robustness), roadrunner_http1 (parsers never-crash + incremental-feed equivalence), roadrunner_conn_loop (random recv / drain / stray inputs, clean exit + slot release), and request_id consistency between request_start / request_stop telemetry.

Malformed-input corpus: roadrunner_http1_corpus_tests exercises HTTP/1.1 patterns lifted from the llhttp test corpus and the canonical request-smuggling vectors documented by PortSwigger.

Conformance harnesses (run on-demand, not part of make precommit):

  • scripts/h2spec.sh — HTTP/2 (RFC 9113 + RFC 7541). Strict 100 % pass.
  • scripts/autobahn.escript — WebSocket (RFC 6455 + RFC 7692). Strict 100 % across the full Autobahn|Testsuite fuzzingclient matrix, no exclusions.
  • scripts/redbot.escript — HTTP/1.1 response hygiene via REDbot.

Benchmarking notes

Two complementary load drivers ship in this repo:

  • scripts/bench.escript — closed-loop. Each worker sends a request, waits for the response, sends the next. Reports throughput + p50/p99 from per-request timing. Easy to set up, no external dependency, but tail latency under load is deflated by Coordinated Omission. Used for the per-scenario matrix in docs/bench_results.md.
  • scripts/wrk2_bench.sh — open-loop, via wrk2 running in Docker (cylab/wrk2:latest). Issues requests at a fixed rate regardless of server response and reports Coordinated-Omission-corrected HdrHistogram percentiles. Output: docs/wrk2_results.md. Needs docker on PATH and rebar3 as test compile already done; the script pulls the image automatically.

Run a quick wrk2 sanity check:

./scripts/wrk2_bench.sh --quick --scenarios hello

The full matrix takes ~2 hours at --runs 1 --duration 30s and ~10 hours at the canonical --runs 3 --duration 60s. Run on a quiet machine — system noise inflates tail percentiles.

Both drivers' internals (worker model, latency aggregation, loader-as-bottleneck conditions) are documented in docs/bench_internals.md.

License

Roadrunner is licensed under the Apache License Version 2.0, for all code.

Reporting a bug

Roadrunner is not perfect software and will be buggy.

Bugs can be reported via GitHub issues: bug report.

Some contributors and maintainers may be unpaid developers working on Roadrunner, in their own time, with limited resources. We ask for respect and understanding, and will provide the same back.

If your contribution is an actual bug fix, we ask you to include tests that, not only show the issue is solved, but help prevent future regressions related to it.

Requesting or implementing a feature

Before requesting or implementing a new feature, do the following:

  • search, in existing issues (open or closed), whether the feature might already be in the works, or has already been rejected,
  • make sure you're using the latest software release (or even the latest code, if you're going for bleeding edge).

If this is done, open up a GitHub issues: feature request.

We may discuss details with you regarding the implementation, and its inclusion within the project.

We try to have as many of Roadrunner's features tested as possible. Everything that a user can do, and is repeatable in any way, should be tested, to guarantee backwards compatible.

Submitting your changes

Code Style

  • run rebar3 fmt (also part of the precommit gate) — erlfmt enforces no trailing whitespace, 4-space indentation, and a 100-character soft line limit
  • write small functions whenever possible, and use descriptive names for functions and variables
  • comment tricky or non-obvious decisions made to explain their rationale
  • prefer modern OTP idioms — sigils for binary literals (~"..."), triple-quoted multi-line strings ("""..."""), maybe expressions for nested case chains, body recursion (cons on the way out) over lists:reverse(Acc), binary keys for wire-derived data (no binary_to_atom on parsed names)

Committing your changes

Merging to the main branch will usually be preceded by a squash.

Commit messages use a plain imperative subject line — no feat:/fix:/chore: semantic prefixes. Subject only, no body unless the change genuinely needs explanation (a one-line subject beats a paragraph of preamble).

While it's OK (and expected) for your commit messages to relate the why of a given change, be aware that the final commit (the merge one) will be the PR title — so make it specific. This also helps automated changelog generation.

Pull requests and branching

All fixes to Roadrunner end up requiring a +1 from one or more of the project's maintainers.

During the review process, you may be asked to correct or edit a few things before a final rebase to merge things. Do send edits as individual commits to allow for gradual and partial reviews to be done by reviewers.

Credits

Roadrunner has been improved by many contributors!