Suave 1.0 was recently released after several years of active development. InfoQ reached out with Henrik Feldt, maintainer of Suave and CEO of qvitoo, to learn more about its capabilities and development history.
InfoQ: How did Suave development get started?
HF: The first commit to Suave was started about 6 years ago by Ademar Gonzales. I came in about 2 years ago after searching for a web server that would suit my use-case of puppet-deployed F# micro-services on both Windows and Linux. At that point, Suave had laid dormant for a few years, but I liked its understandable code-base.
At that point there were stability issues; Ademar was very responsive and whenever I wrote a unit-test or repro he would fix it very fast; often overnight.
This turned into a very productive cooperation. So from my perspective this was the first, very positive interaction. About 2 months later, after a lot of testing, we deployed to production. After a little snag, about a week into the deployment, Suave was a match for its name; smooth.
InfoQ: How can a sizable Suave application be structured to handle several hundred of routes while keeping maintainability?
HF: I normally structure it so that each route's prefix is a different F# module, with Filters.pathStars. That way I can easily scan my App.fs for the prefix I'm interested in changing or looking at during development. App.api is a large `choose` list and any orthogonal concerns like authentication can be placed around this list of routes, using the `context` function.
For each of the modules, e.g. Accounts, there's Accounts.api which lists all verb+path combinations (+ other filters). Each line in this 'choose' list is responsible for generating a reply to the caller, even if it's a validation failure (done with 'bindReq).
At the very bottom of App.api's list of prefixes/locations, is the usage of the Files module, so that if an API route doesn't match, at least the request can be for a static file. For qvitoo, if the file wouldn't be found, it always matches anyway and returns index.html. Because we're using React.JS with react-router, it then becomes the job of react-router to deep-link/navigate into the app and find the right page.
This setup gives us a very flexible way of adding more routes. Maintainability with Suave is not something to worry about, because the library stays out of your way and lets you get on with life.
Another method would be to auto-generate the routes with tools like this generator://github.com/rayokota/generator-angular-suave. In the same lines, I think in the future some kind of meta-programming would be useful here (like camlp4).
InfoQ: What would be the scenarios Suave is most suited for?
Building web apps, of course! You can build anything, from an API, to a micro-service, to a large web site. Or you could use it in a server-type F#/C# CLR app, as an entry point to your CLR clients. Or use it to expose /health in your TopShelf Windows service together with Logary, to make life easier for operations.
InfoQ: What is the setup required on a server to run a Suave application?
HF: You need Mono or .Net. Then you run your fsx file or your exe file. That's it!
Most of the trouble comes down to ensuring that your server keeps that exe running without being logged in.
If you're on Windows you can either run TopShelf (there's an example in our repo on GitHub), or you can run winsw and just point directly to your console application. Suave itself is very stable, so you can run these micro-services for very long periods of time without manual intervention.
At qvitoo we do all of our development on OS X and stage and deploy to a mixture of CentOS, Ubuntu and to some extent CoreOS. When we run on Linux, all that's needed is an entry in the process manager of your choice. For us, that's systemd, so for qvitoo.com we write a qvitoo.service file that looks like this:
[Unit] Description=Logibit Qvitoo Wants=bus-org.freedesktop.NetworkManager.target After=bus-org.freedesktop.NetworkManager.target [Service] EnvironmentFile=/etc/sysconfig/qvitoo User=qvitoo ExecStart=/opt/qvitoo/start Restart=always RestartSec=5
I think a lot of the up-take that Suave is having right now is because Suave is so very easy to get started with.
Of course, you could also deploy to Heroku, a very easy way to get started so you don't have to manage servers at all. You can use Azure too, if that tickles your fancy.
InfoQ: What would be the highlights of the past years leading to this first major release?
A few milestones were:
- Getting the first version, 0.0.2 published as a NuGet package.
- Getting the documentation and suave.io web site designed - this helped a lot and got people intereste
- Fully documenting the public API; the HTTP combinators are fully documented from the HTTP RFCs
- Great stability improvements with Ademar's monadic socket builder.
- 0.10 had Server Sent Events support.
- Around 0.16 we started getting people interested, getting tweets about Suave.
- 0.19 had support for cryptographically strong session state and state storage in cookies.
- 0.20 had a great API reorg that became popular and easier to understand.
- 0.21 fixed the last buffer leaks under stress.
- At 0.25 the project had Don Syme's interest. We got a free API review and a nice big PR that improved many small things.
- 0.26 had Razor support.
- 0.27 had WebSocket support!
- 0.32 with OWIN support made it possible to support lots of use cases from the rest of the community.
- 0.33 created the LibUV tcp factory.
- 1.0 with API stability and a managed-code implementation of TLS (from the framework).
InfoQ: Do you have any data on Suave's performance?
HF: In qvitoo's event-sourced DDD/CQRS-system, running on modern hardware, we normally get sub-millisecond latencies for writes. Reads are similarly very fast and performance latencies are dominated by any IO that we do to other subsystems.
Suave has never been benchmarked, but up to v1 aimed to set a nice functional API that's really easy to use and get started with. We're hoping that as Suave become more widely used for high-throughput sites and services, we'll see more performance contributions.
On OS X on a laptop that also generates the load, I have it serving Hello World 5600 times per second. Hypothetically, we could get another magnitude of throughput performance by moving to an async framework like Hopac that doesn't allocate as much as F#'s async and perhaps then another magnitude by being even smarter with object allocations profiling the critical path.
If a reader feels like this would be an interesting challenge, we merge PRs frequently and fast or otherwise provide lots of feedback on what is needed to merge, to make contributing fun and easy even for newbies to do.
InfoQ: Do you have a roadmap for what's coming next?
HF: We're going to support HTTP2. We're discussing what we can do to bump performance one or two magnitudes by doing fewer memory allocations, perhaps by moving towards Hopac which has higher async performance than the built-in F# async.
There's a pull request with CoreCLR support from the F# team waiting to be merged when the tooling around CoreCLR for F# has settled a bit.
It would also be useful to have the same SocketOp programming model for an all-F# HTTP client, which could be made to fit perfectly around unit-testing and integration-testing Suave web sites and APIs.
F* as a language is maturing; if Suave could compile under it, then perhaps Suave web sites can be written and compiled to something Mirage, the exo-kernel can run? Or we could compile Suave web sites to native code to run without libraries.
We'd like to provide a good use-case for deploying on Mono or CoreCLR on Alpine linux. After a stint a few months ago, mono is in their testing-repo. That would make a Suave service deployment around 5 MiB for the OS and 30 MiB for CoreCLR and 5 MiB for the service.
InfoQ: Anything else you would like to add?
HF: If you're a skilled developer and interested in working with exciting technologies such as F#, Suave and AI and web, you may be a good fit for working at qvitoo. Send an e-mail to hi@qvitoo.com.
If you want to learn more about how to write Suave code and F# in general, you can sign up to F# TV. By doing so you're also helping towards building and maintaining Suave.