Use a shared reference between actix-web and another thread

Do you know an example showing a clean way to share a reference between actix-web and another thread ?
I'm able to declare a lazy_static variable and then share the ref between a thread and actix, but I find this solution quite ugly and would like to improve it.

The usecase is to share the ref of a struct wrapping a Dashmap between a thread building the hashmap and actix-web allowing (among other things) to query it.

If I try to pass a ref using actix data or app_data, I get a "App data is not configured, to configure use App::data()" and if I clone it I get another instance of my variable which is not what I want.

Any ideas ?

You generally can't share anything between threads using Rust references (&), which are temporary shared borrows (except scoped-thread abstraction, but that doesn't apply to actix where you don't control the threads directly).

In multi-threaded environments Arc is the most common type of shared reference to use. If you wrap your app data in Arc, you will be able to hold on to it from any thread.

To be able to mutate the data from any thread, you will also need to wrap it in Mutex, or use some other lock or interior mutability primitive. For example, for updating server config in Actix I use ArcSwap.

Also be aware that state shared in such a way is quite possibly a performance bottleneck.

That won't matter much if only 1 handler is active at once, but if performance matters you'll likely want to solve this issue in a different way, without using mutable shared state.

Thanks a lot, actually, the struct was already thread-safe, and simply wrapping the Dashmap in Arc did the job ! :slight_smile:

Performance of the server is not an issue since it's supposed to be used locally but I'm curious, what would you advise, instead ?

Depending on the exact use case, either a DB that can handle multiple connections concurrently, a concurrent KV store, or a multithreaded queue like the one provided by crossbeam-channel with one side available to handlers (shared with a Data<T> provided by actix_web) and the other side yet another thread that is dedicated to handling that.

The pattern here is that the first 2 are completely external to the actix process, and the last one is as much separated from the rest as possible without causing contention. Also, all of these options have in common that the handlers generally don't block each other except in edge cases (e.g. more threads than physical CPU cores mean sharing and contention).

1 Like