This website has been ported from Rocket to Axum, and it's been a joy.
Notable steps during the refactoring
Some MIME types needed to be handled manually. For instance, serving an SVG
should have the type image/svg+xml
and browsers may not render them correctly
in places such as background images otherwise.
The configuration mechanism built into Rocket, it differentiates between
development and deployment environment with differing security levels and other
differences in the profile, is not builtin. To avoid breakage, the new
application still reads the old ROCKET_*
environment variables.
The Response
handling changed significantly. Rocket provides a high degree of
flexibility at the definition site. Your handles can have any result type,
bounded by a trait, and Rocket tries lets you get away even with rather
ambiguous semantics such as returning a borrowed str
. Here, axum
is a
little stricter. Its IntoResponse
type makes sure that some definition of at
least a status code is present and bodies are built around streams of Bytes
much more explicitly. You get less surprise copies of data but this
necessitated a bit of implementation rework. For instance, the internal
representation of the pre-rendered in-memory cache now also utilized Bytes
directly.
On a related note, from a performance perspective it would be appropriate to have
AsyncRead
here. The network queue provides buffers which are to be filled with fragments of the headers and response bodies. Techniques such as pre-registered IO-uring buffers will not work when the handler returns some new allocation anyways. And having the user dynamically and freely allocate from such a precious resource is a huge DOS risk.
The old binary still compiled perfectly, but a dependency update revealed that version resolution does not respect the Rust Version. I've gone ahead and bumped to the current stable, as well as gone through all dependencies. Surprisingly, conflicts were rather rare and most interfaces quite stable even across versions that, by SemVer, did not need to be. Updating also accordingly allowed bumping to Edition 2021.
New changes
The server now provides metrics, available behind an API secured with an OAuth
Bearer token. None of these metrics store or utilize any personally
identifiable information. Different requests are not correlated. No cookie
banner will be introduced. Utilizing the metered
crate will
give me an idea of the hit-count of articles, and server resource usage such as
in-flight requests, memory, CPU.
Maybe I'll stream that to a prometheus but it just looks stupidly complicated. But there's serde_prometheus for its idiosyncratic Text format and maybe it can be deployed in a neat little sandbox. Appropriately, the license for that crate is WTFPL.
The project pages are now generated from Markdown, same as articles, with their own little pages coming shortly. I've also started actually writing down something for most of the projects started in the last 4 years or so. And it'll get a redesign as some of the web-based projects should shine by including their showcases inline. Nothing's finalized yet to be shown.
For tracing, I'm not looking forward to integrating tracing
. It's a bit
infant and I understand the use case they're aiming for but it's not ready for
async
in the shape it should be. Globals and macros everywhere and you're
going mad if trying to talk directly to their main subscriber trait. (The name
confusion in the jump 0.1 -> 0.2
will also be quite something, I'm going to
avoid that by waiting).
Final thoughts
The change from Rocket to Axum has had surprisingly little impact on any of the user-facing interfaces. This allowed me to clean up some architecture along the way. With some of the remaining code duplication, I've been tempted to move part of my pre-rendering process into WASM modules to be shipped to the page with the content. This would turn the whole thing into much more of a CMS than it is now. There's going to be interesting times for WebAssembly ahead.