Non-Tokio-based Web App frameworks?

Hey all,

At work, we're currently dealing with some code that talks to some Hardware Security Modules (HSM). The overall application is written in Java, and we use a third-party library to talk to the HSM. This third-party library has to use JNI calls to talk to the HSM, and is overall rather unpleasant to use[1]. We're currently looking into whether it has an available C (or C++) library that would be less awful to use, and if so, whether it would be sensible to introduce Rust into the team for this, as only one person has any real experience with C/etc.

The reason I'm asking the question is that one avenue I'd be exploring is having the Rust/C integration be exposed as a REST/HTTP RPC API, and if that's the case, 99% of the work would be either CPU bound (doing crypto work), or blocking TCP (talking to the HSM over the network), since I don't imagine it would be possible for us to tell the HSM library to use epoll if it wasn't designed with that in mind from day one.

I believe I could use Actix and its actor model to do all the work on another thread that's allowed to block. Another possibility, given that the code should be pretty straightforward, would be to use a blocking web framework, with one thread per request and not have to involve futures at all (which I honestly still find frustrating to use), but as far as I can tell, all the popular web frameworks use Hyper (or just Tokio) under the hood (e.g. Actix, Iron, Rocket, Gotham, etc)...

[1] The HSM is accessed over the network, and the Java library doesn't talk to it directly - rather, it calls a native library loaded via JNI (yay), which talks to a side-car process (double-yay), which talks to the HSM. The environment we're deploying to does not like an application having more than one process, so this is making our lives a bit difficult. Ideally, if we can use the C library directly, we could get rid of the side car process, making our deployment a lot simpler!

Any async library in rust (web or not) will tend to use Tokio, simply because it's the path of least resistance: it's already here, is reasonably ergonomic, and tends to provide the features one wants when using async.

If you can't get away with using a non-async library like Rocket, then chances are you'll have to write something yourself.

However, before you do that be sure to take a look at this, it provides an overview of the Rust-based web library ecosystem.

1 Like

Having an async http server doesn't preclude delegating CPU-intensive tasks to another thread.

In my Rust webapp playground I'm using a thread-pool (yeah, provided by Tokio) for blocking SQL queries with Diesel. Despite using actix-web as the server, I did not wanted to use its actors as I find that declaring messages types, matching on them etc requires too much boilerplate compared to a simple closure.

1 Like

Is Rocket not async/non-blocking? I couldn't see a definitive answer either way on the website, but it includes Hyper in its dependency list, which, AFAIK, uses Tokio under the hood?

That's true - thanks for your suggestion about thread-pool. How do you handle the case where the thread-pool is overwhelmed with requests? Does the actix-web runner block until one of the threads in the thread pool frees up?

How do you handle the case where the thread-pool is overwhelmed with requests?

With pool_size() you set the upper bound of the number of threads (they're created on demand) and the thread pool will return an error when trying to run a task, which you can then turn into a 503 Service Unavailable response.

Note that my code, as it is, will panic when we exceed capacity (and thus have actix return a 500), since spawn_fn "will panic if the instance of Spawn provided is unable to spawn the future provided".

1 Like

As @swallez mentioned, it’s not because your web framework uses async i/o to handle requests/responses that the C library you’re calling mid-request needs to be non-blocking. Most web frameworks will already be multi-threaded so you probably don’t even need to delegate work to a thread pool but can simply have your request handler block.

1 Like