mtrudel

mtrudel

Creator of Bandit

Bandit - a pure Elixir HTTP server for Plug & WebSock applications

Bandit is an HTTP server for Plug and WebSock apps.

Bandit is written entirely in Elixir and is built atop Thousand Island. It can serve HTTP/1.x, HTTP/2 and WebSocket clients over both HTTP and HTTPS. It is written with correctness, clarity & performance as fundamental goals.

In ongoing automated performance tests, Bandit’s HTTP/1.x engine is up to 4x faster than Cowboy depending on the number of concurrent requests. When comparing HTTP/2 performance, Bandit is up to 1.5x faster than Cowboy. This is possible because Bandit has been built from the ground up for use with Plug applications; this focus pays dividends in both performance and also in the approachability of the code base.

Bandit also emphasizes correctness. Its HTTP/2 implementation scores 100% on the h2spec suite in strict mode, and its WebSocket implementation scores 100% on the Autobahn test suite, both of which run as part of Bandit’s comprehensive CI suite. Extensive unit test, credo, dialyzer, and performance regression test coverage round out a test suite that ensures that Bandit is and will remain a platform you can count on.

Lastly, Bandit exists to demystify the lower layers of infrastructure code. In a world where The New Thing is nearly always adding abstraction on top of abstraction, it’s important to have foundational work that is approachable & understandable by users above it in the stack.

Project Goals

  • Implement comprehensive support for HTTP/1.0 through HTTP/2 & WebSockets (and beyond) backed by obsessive RFC literacy and automated conformance testing
  • Aim for minimal internal policy and HTTP-level configuration. Delegate to Plug & WebSock as much as possible, and only interpret requests to the extent necessary to safely manage a connection & fulfill the requirements of safely supporting protocol correctness
  • Prioritize (in order): correctness, clarity, performance. Seek to remove the mystery of infrastructure code by being approachable and easy to understand
  • Along with our companion library Thousand Island, become the go-to HTTP & low-level networking stack of choice for the Elixir community by being reliable, efficient, and approachable

https://github.com/mtrudel/bandit

First 10 of 30 Posts Switch mode

mtrudel

mtrudel OP

Creator of Bandit

All,

After several years of effort, I just published version 1.0.0 of both the Bandit and Thousand Island libraries. Folks that are depending on versions in the 0.x.y or 1.0.0-pre series of either library should update your dependencies to be ~> 1.0.

This has been a ton of work, and has been made possible in large part due to the help of tons of contributors. In particular, @moogle19, @ryanwinchester and @alisinabh have gone above and beyond on all fronts. The project wouldn’t be the success it is without help from folks like them. Thanks all!

I put together a bit of a retrospective blog post about the whole journey here, if anyone cares to learn more!

76
Post #1
Eiji

Eiji

I have tried bandit only once. There was some simple bug, but it was hard to debug. For some reason my instinct suddenly directed me to this library. What’s funny I read about it only once before and I simply forgot its name, but somehow I have managed to find it on forum. :sweat_smile:

Anyway, bandit’s error handling was an amazing help which saved me a lot of energy and time. Been waiting for a stable 1.x release, so I could use it by default. Thanks! :heart:

kwando

kwando

Well done guys and congratz on 1.0! Been using ThousandIsland for a small hobby project of mine and it works great :slight_smile:

Hisako1337

Hisako1337

Awesome effort! And I‘ll definitely upgrade to it right away! Thank you so much!

But one question I have still: what are the typical performance improvements one can expect with an ordinary liveview app? I have no good estimate how much time per route is spent in the http layer vs other parts of the pipeline. Anyone ideas?

mtrudel

mtrudel OP

Creator of Bandit

Excellent question and one I get a lot. The short answer is that in most cases you probably won’t see much of a difference between Bandit and Cowboy from a performance perspective; your plug’s implementation is going to be the dominant factor in overall performance, and switching out the underlying server won’t magically make that work go away.

That having been said, there are many workloads in which you could expect to see a benefit to Bandit. The ideal case would be large numbers of HTTP/1 clients doing lots of IO on very short lived connections. In that case you could see some substantial benefits (see my latest benchmark for more).

Some workloads are going to be worse. In particular, HTTP/2 performance in Bandit is pretty awful at the moment, but is going to be getting a lot of attention as part of the work to add WebSockets over HTTP/2 (RFC 8441) support. This will be one of the next things I’m working on.

In terms of LiveView, Bandit’s WebSocket implementation is generally a little bit faster than Cowboy’s (around 10-20%). You might see some real-world benefit there; it really depends on your particular usage patterns.

martosaur

martosaur

@mtrudel Hi :wave:
I was digging into Absinthe today and noticed it has a code path that results in a process just exiting when a certain internal timeout is exceeded. From Bandit perspective, this results in this kind of error:

15:08:27.012 [error] GenServer #PID<0.1581.0> terminating
** (stop) :foobar
    bandit.exs:13: anonymous fn/2 in Router.do_match/4
    /Users/amartsinovich/Library/Caches/mix/installs/elixir-1.17.3-erts-15.1.3/5a1480805a98346fc77508013de370cc/deps/plug/lib/plug/router.ex:246: anonymous fn/4 in Router.dispatch/2
    (telemetry 1.3.0) /Users/amartsinovich/Library/Caches/mix/installs/elixir-1.17.3-erts-15.1.3/5a1480805a98346fc77508013de370cc/deps/telemetry/src/telemetry.erl:324: :telemetry.span/3
    /Users/amartsinovich/Library/Caches/mix/installs/elixir-1.17.3-erts-15.1.3/5a1480805a98346fc77508013de370cc/deps/plug/lib/plug/router.ex:242: Router.dispatch/2
    bandit.exs:6: Router.plug_builder_call/2
    (bandit 1.6.1) lib/bandit/pipeline.ex:127: Bandit.Pipeline.call_plug!/2
    (bandit 1.6.1) lib/bandit/pipeline.ex:36: Bandit.Pipeline.run/4
    (bandit 1.6.1) lib/bandit/http1/handler.ex:12: Bandit.HTTP1.Handler.handle_data/3
Last message: {:continue, :handle_connection}
State: {%ThousandIsland.Socket{socket: #Port<0.22>, transport_module: ThousandIsland.Transports.TCP, read_timeout: 60000, silent_terminate_on_error: false, span: %ThousandIsland.Telemetry{span_name: :connection, telemetry_span_context: #Reference<0.2186918947.463994885.242980>, start_time: -576460734287898010, start_metadata: %{remote_address: {127, 0, 0, 1}, remote_port: 53034, telemetry_span_context: #Reference<0.2186918947.463994885.242980>, parent_telemetry_span_context: #Reference<0.2186918947.463994885.242884>}}}, %{opts: %{http: [], websocket: [], http_1: [], http_2: []}, plug: {Router, []}, handler_module: Bandit.InitialHandler, http_1_enabled: true, http_2_enabled: true}}

My understanding is that there’s not much Bandit can do here in terms of error handling and in general using exit isn’t the best way of handling this kind of case. But I was wondering, if it’s a good idea to define terminate callback for handler and issue a telemetry event? WDYT?

mtrudel

mtrudel OP

Creator of Bandit

Yep, we can do better here. The work that grzuy did in fix: throwing plug properly handled and returns 500 by grzuy · Pull Request #411 · mtrudel/bandit · GitHub makes this nearly trivial. I’ll get a PR worked up to improve this.

mtrudel

mtrudel OP

Creator of Bandit

Fixed on main. Will go out in the next release.

Thanks for bringing this up @martosaur !

awksedgreep1

awksedgreep1

Hey Matt,
Any thoughts on what may have been the bottleneck here? Seems we ran up the CPU as well.

Where Next?

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
387 14960 120
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

Other Trending Topics Top

type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
bjorng
We want to introduce a new native datatype to Erlang: native records. Although replacing all tuple records with native records is not our...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New

We're in Beta

About us Mission Statement