We're wondering though if there are good decision criteria when to use the actor pattern vs. spawning a Future + Send + 'static directly to the Tokio runtime (and wait on the corresponding JoinHandle as opposed to waiting for data appearing on the oneshot::Receiver) ?
In Rust, the actor pattern is for when you have some mutable state that persists across requests to the actor. In that case, independent spawned tasks will not suffice since they have no place to keep the state. If there is no mutable state, conversely, you probably don't need an actor (unless it serves a purpose of throttling resource consumption by introducing sequentiality).
Spawned tasks that lock a shared Mutex for as long as they run are externally indistinguishable from an actor, but less efficient and elegant.
In our case we indeed have a shared mutable state (which we want to keep alive between requests) but that state is not Send nor Sync. What we're doing so far is instantiate it as thread_local! but then use it with a Tokio runtime with only one worker thread (so only one instance of the shared mutable state is created).
I see. Presumably your thread-local contains a RefCell or something else to allow mutation.
You have essentially built something halfway to an actor already. If you use an actor then you can eliminate the thread_local and RefCell, and it will be cheaper than an entire Tokio runtime and accompanying thread.