Why does function block even though it is moved into new thread - rust

I have been following the guide https://doc.rust-lang.org/book/ch20-02-multithreaded.html#simulating-a-slow-request-in-the-current-server-implementation
The guide states that a call to '/sleep' will block and calls to '/' will not block. However I don't understand why additional calls made to '/sleep' are also blocked? Surely as each connection is moved into a new thread with thread::spawn there is no reason for 2 separate calls to '/sleep' to block each other? How does the thread even know which endpoint is being called?
I have stripped down the code from the tutorial and I found that if you move the thread::sleep line above stream.read() it will not block. If that line is after stream.read() then each connection seems to be on the same thread and is blocked despite being in a new thread created with thread::spawn().
use std::io::prelude::*;
use std::net::TcpStream;
use std::net::TcpListener;
use std::thread;
use std::time::Duration;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
thread::spawn(move || {
handle_connection(stream);
});
}
}
fn handle_connection(mut stream: TcpStream) {
let mut buffer = [0; 512];
// thread::sleep(Duration::from_secs(5)); // Doesn't block here (before steam.read())
stream.read(&mut buffer).unwrap();
thread::sleep(Duration::from_secs(5)); // Blocks here (after steam.read())
let response = "HTTP/1.1 200 OK\r\n\r\n";
stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
If you run the above code and open up a few browser tabs to localhost:7878 each connection is blocked and has to wait for the earlier one to resolve.
If you move the thread::sleep() line to be above stream.read() it will no longer block. So it seems to be something with the stream.read line but I cannot understand why. Can anyone help me to understand please?

Related

Running an actix web server on a separate thread

I'm new to actix, and I'm trying to understand how I can run a server on one thread and send requests from another.
This is the code I have so far
use actix_web::{web, App, HttpResponse, HttpServer};
use std::{sync::mpsc::channel, thread};
#[actix_web::main]
async fn main() {
let (tx, rx) = channel();
thread::spawn(move || {
let srv =
HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
.bind("localhost:12347")
.unwrap()
.run();
let _ = tx.send(srv);
});
reqwest::get("http://localhost:12347").await.unwrap();
let srv = rx.recv().unwrap();
srv.handle().stop(false).await;
}
It compiles just fine, but it gets stuck on on sending the request. It seems like the server is running, soI can't figure out why I am not getting a response.
EDIT: As suggested by #Finomnis and #cafce25,I changed the code to use tasks instead of threads, and awaited te result of .run()
use actix_web::{web, App, HttpResponse, HttpServer};
use std::{sync::mpsc::channel, thread};
#[actix_web::main]
async fn main() {
let (tx, rx) = channel();
tokio::spawn(async move {
let srv =
HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
.bind("localhost:12347")
.unwrap()
.run();
let _ = tx.send(srv.handle());
srv.await.unwrap();
});
reqwest::get("http://localhost:12347").await.unwrap();
let handle = rx.recv().unwrap();
handle.stop(false).await;
}
which solves the problem. I'm still curious if it is possible to do it on different threads since I can't use await inside a synchronous function.
There are a couple of things wrong with your code; the biggest one being that you never .await the run() method.
For that fact alone you cannot run it in a normal thread, it has to exist in an async task.
So what happens is:
you create the server
the server never runs because it doesn't get awaited
you query the server for a response
the response never comes because the server doesn't run, so you get stuck in reqwest::get
What you should do instead:
start the server.
Also:
You don't need to propagate the server object out to stop it. You can create a .handle() first before you move it into the task. The server handle does not contain a reference to the server, it's based on smart pointers instead.
NEVER use synchronous channels with async tasks. It will block the runtime, dead-locking everything. (The only reason it worked in your second example is because it is most likely a multi-threaded runtime and you only dead-locked one of the runtime cores. Still bad.)
(Maybe) don't tokio::spawn if you use #[actix_web::main]. actix-web has its own runtime, you need to actix_web::rt::spawn with it. If you want to use tokio based tasks, you need to do #[tokio::main]. actix-web is compatible with the tokio runtime. (EDIT: actix-web might be compatible with tokio::spawn(), I just didn't find documentation anywhere that says it is)
With all that fixed, here is a working version:
use actix_web::{rt, web, App, HttpResponse, HttpServer};
#[actix_web::main]
async fn main() {
let srv = HttpServer::new(|| App::new().default_service(web::to(|| HttpResponse::NotFound())))
.bind("localhost:12347")
.unwrap()
.run();
let srv_handle = srv.handle();
rt::spawn(srv);
let response = reqwest::get("http://localhost:12347").await.unwrap();
println!("Response code: {:?}", response.status());
srv_handle.stop(false).await;
}
Response code: 404

the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<i32>

I'm attempting to build a multithreaded application using MPSC and I'm running into the error in the title. I'm not sure what the proper pattern for this use case is - I'm looking for a pattern that will allow me to clone the producer channel and move it into a new thread to be used.
This new thread will keep an open websocket and send a subset of the websocket message data through the producer whenever a websocket message is received. Data from other threads will be needed in the consumer thread which is why I assume the MPSC pattern is a suitable choice.
In addition to the message in the title it also shows these:
`std::sync::mpsc::Sender<i32>` cannot be shared between threads safely
help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender`
Can/should I implement Send for this? Is this an appropriate time to use Rc or Pin? I believe this is happening because I'm attempting to send a type that doesn't implement Send across an .await in an async closure, but I don't what to make of it or what to reach for in this situation.
I've been able to reduce my issue down to this:
use futures::stream::{self, StreamExt};
use std::sync::mpsc::{channel, Receiver, Sender};
#[tokio::main]
async fn main() {
let (tx, rx): (Sender<i32>, Receiver<i32>) = channel();
tokio::spawn(async move {
let a = [1, 2, 3];
let mut s = stream::iter(a.iter())
.cycle()
.for_each(move |int| async {
tx.send(*int);
})
.await;
});
}
There are several issues with your code. The first is that you're missing a move in the innermost async block, so the compiler tries to borrow a reference to tx. That's why you get the error that Sender (type of tx) doesn't implement Sync.
Once you add the missing move you get a different error:
error[E0507]: cannot move out of `tx`, a captured variable in an `FnMut` closure
Now the issue is that for_each() will call the closure multiple times, so you are actually not allowed to move tx into the async block - because there would be nothing to move after the first invocation of the closure.
Since MPSC channels allow multiple producers, Sender implements Clone, so you can simply clone tx before moving it to the async block. This compiles:
let (tx, _rx): (Sender<i32>, Receiver<i32>) = channel();
tokio::spawn(async move {
let a = [1, 2, 3];
let _s = stream::iter(a.iter())
.cycle()
.for_each(move |int| {
let tx = tx.clone();
async move {
tx.send(*int).unwrap();
}
})
.await;
});
Playground
Finally, as pointed out in the comments, you almost certainly want to use async channels here. While the channel you create is unbounded, so senders will never block, the receiver will block when there are no messages and therefore halt a whole executor thread.
As it happens, the sender side of tokio MPSC channels also implements Sync making code close to the one from your question compile:
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
tokio::spawn(async move {
let a = [1, 2, 3];
let _s = stream::iter(a.iter())
.cycle()
.for_each(|int| async {
tx.send(*int).unwrap();
})
.await;
});
assert_eq!(rx.recv().await, Some(1));
assert_eq!(rx.recv().await, Some(2));
assert_eq!(rx.recv().await, Some(3));
Playground

Rust Single threaded Persistent TCP Server

I'm trying to make a server in Rust using tcp protocol. I can make a normal server, through the language documentation, but I don't want that whenever a new connection is made, a new thread is created, nor do I want to use a thread pool, because the tcp connections will be persistent, that is, they will last a long time (around 30min-2h). So, I looped over all the connections and, with a 1 millisecond timeout, I try to read if there are any new packets. However, something tells me this is not the right thing to do. Any idea?
Thanks in advance.
You are probably looking for some asynchronous runtime. Like most runtimes, tokio can be customized to work with a single thread, if you don't have many connections you centainly don't need more than one. If we translate the example #Benjamin Boortz provided:
use tokio::io::*;
use tokio::net::{TcpListener, TcpStream};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").await.unwrap();
while let Ok((stream, _address)) = listener.accept().await {
// this is similar to spawning a new thread.
tokio::spawn(handle_connection(stream));
}
}
async fn handle_connection(mut stream: TcpStream) {
let mut buffer = [0; 1024];
stream.read(&mut buffer).await.unwrap();
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
}
This code is concurrent, yet single threaded, which seems to be what you want. I recommend you check the tokio tutorial. It is a really good resource if you are unfamiliar with asynchronous programming in Rust.
not sure if this is what you need but you can find in "The Rust Programming Language" Book an example for a single threaded TCP Server. https://doc.rust-lang.org/book/ch20-01-single-threaded.html
Please refer to Listing 20-2:
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream in listener.incoming() {
let stream = stream.unwrap();
handle_connection(stream);
}
}
fn handle_connection(mut stream: TcpStream) {
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
println!("Request: {}", String::from_utf8_lossy(&buffer[..]));
}
Ref: https://doc.rust-lang.org/book/ch20-01-single-threaded.html#reading-the-request

Can a Tokio task terminate the whole runtime gracefully?

I start up a Tokio runtime with code like this:
tokio::run(my_future);
My future goes on to start a bunch of tasks in response to various conditions.
One of those tasks is responsible for determining when the program should shut down. However, I don't know how to have that task gracefully terminate the program. Ideally, I'd like to find a way for this task to cause the run function call to terminate.
Below is an example of the kind of program I would like to write:
extern crate tokio;
use tokio::prelude::*;
use std::time::Duration;
use std::time::Instant;
use tokio::timer::{Delay, Interval};
fn main() {
let kill_future = Delay::new(Instant::now() + Duration::from_secs(3));
let time_print_future = Interval::new_interval(Duration::from_secs(1));
let mut runtime = tokio::runtime::Runtime::new().expect("failed to start new Runtime");
runtime.spawn(time_print_future.for_each(|t| Ok(println!("{:?}", t))).map_err(|_| ()));
runtime.spawn(
kill_future
.map_err(|_| {
eprintln!("Timer error");
})
.map(move |()| {
// TODO
unimplemented!("Shutdown the runtime!");
}),
);
// TODO
unimplemented!("Block until the runtime is shutdown");
println!("Done");
}
shutdown_now seems promising, but upon further investigation, it's probably not going to work. In particular, it takes ownership of the runtime, and Tokio is probably not going to allow both the main thread (where the runtime was created) and some random task to own the runtime.
You can use a oneshot channel to communicate from inside the runtime to outside. When the delay expires, we send a single message through the channel.
Outside of the runtime, once we receive that message we initiate a shutdown of the runtime and wait for it to finish.
use std::time::{Duration, Instant};
use tokio::{
prelude::*,
runtime::Runtime,
sync::oneshot,
timer::{Delay, Interval},
}; // 0.1.15
fn main() {
let mut runtime = Runtime::new().expect("failed to start new Runtime");
let (tx, rx) = oneshot::channel();
runtime.spawn({
let every_second = Interval::new_interval(Duration::from_secs(1));
every_second
.for_each(|t| Ok(println!("{:?}", t)))
.map_err(drop)
});
runtime.spawn({
let in_three_seconds = Delay::new(Instant::now() + Duration::from_secs(3));
in_three_seconds
.map_err(|_| eprintln!("Timer error"))
.and_then(move |_| tx.send(()))
});
rx.wait().expect("unable to wait for receiver");
runtime
.shutdown_now()
.wait()
.expect("unable to wait for shutdown");
println!("Done");
}
See also:
How do I gracefully shutdown the Tokio runtime in response to a SIGTERM?
Is there any way to shutdown `tokio::runtime::current_thread::Runtime`?
How can I stop the hyper HTTP web server and return an error?

How am I supposed to apply a match or Option after an unwrap?

I'm trying to get into Rust from a Python background and I'm having an issue with a PoC I'm messing around with. I've read through a bunch of blogs and documentation on how to handle errors in Rust, but I can't figure out how to implement it when I use unwrap and get a panic. Here is part of the code:
fn main() {
let listener = TcpListener::bind("127.0.0.1:5432").unwrap();
// The .0 at the end is indexing a tuple, FYI
loop {
let stream = listener.accept().unwrap().0;
stream.set_read_timeout(Some(Duration::from_millis(100)));
handle_request(stream);
}
}
// Things change a bit in here
fn handle_request(stream: TcpStream) {
let address = stream.peer_addr().unwrap();
let mut reader = BufReader::new(stream);
let mut payload = "".to_string();
for line in reader.by_ref().lines() {
let brap = line.unwrap();
payload.push_str(&*brap);
if brap == "" {
break;
}
}
println!("{0} -> {1}", address, payload);
send_response(reader.into_inner());
}
It is handling the socket not receiving anything with set_read_timeout on the stream as expected, but when that triggers my unwrap on line in the loop it is causing a panic. Can someone help me understand how I'm properly supposed to apply a match or Option to this code?
There seems to be a large disconnect here. unwrap or expect handle errors by panicking the thread. You aren't really supposed to "handle" a panic in 99.9% of Rust programs; you just let things die.
If you don't want a panic, don't use unwrap or expect. Instead, pass back the error via a Result or an Option, as described in the Error Handling section of The Rust Programming Language.
You can match (or any other pattern matching technique) on the Result or Option and handle an error appropriately for your case. One example of handling the error in your outer loop:
use std::net::{TcpStream, TcpListener};
use std::time::Duration;
use std::io::prelude::*;
use std::io::BufReader;
fn main() {
let listener = TcpListener::bind("127.0.0.1:5432")
.expect("Unable to bind to the port");
loop {
if let Ok((stream, _)) = listener.accept() {
stream
.set_read_timeout(Some(Duration::from_millis(100)))
.expect("Unable to set timeout");
handle_request(stream);
}
}
}
Note that I highly recommend using expect instead of unwrap in just about every case.

Resources