Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only one connection being handled at a time #115

Open
gmbeard opened this issue Apr 19, 2018 · 3 comments
Open

Only one connection being handled at a time #115

gmbeard opened this issue Apr 19, 2018 · 3 comments

Comments

@gmbeard
Copy link
Contributor

gmbeard commented Apr 19, 2018

I believe that the placement of the call to pool.scoped inside the loop statement isn't taking advantage of the thread pool. As it stands, I think only one connection at a time is being processed. The example in the scoped_threadpool documentation suggests that the entire loop be enclosed in the Pool::scoped closure.

simple-server/src/lib.rs

Lines 254 to 269 in 10103f5

loop {
// Incoming is an endless iterator, so it's okay to unwrap on it.
let stream = incoming.next().unwrap();
let stream = stream.expect("Error handling TCP stream.");
stream
.set_read_timeout(Some(Duration::from_millis(READ_TIMEOUT_MS)))
.expect("FATAL: Couldn't set read timeout on socket");
pool.scoped(|scope| {
scope.execute(|| {
self.handle_connection(stream)
.expect("Error handling connection.");
});
});
}

@gmbeard
Copy link
Contributor Author

gmbeard commented Apr 19, 2018

I think this should be an easy fix; Just rearrange the call to pool.scoped(|scope|{ so that it encapsulates the loop { ... }. This is just an observation. I haven't done any testing to prove my theory.

@scurest
Copy link
Contributor

scurest commented Apr 19, 2018

I can confirm this. I tested it with this server

extern crate simple_server;

fn main() {
    use simple_server::Server;
    let server = Server::new(|request, mut response| {
        if request.uri() == "/sleep" {
            std::thread::sleep(std::time::Duration::from_secs(5));
            Ok(response.body(b"Yawn\n".to_vec())?)
        } else {
            Ok(response.body(b"I'm ready!\n".to_vec())?)
        }
    });
    server.listen("127.0.0.1", "7878");
}

If the server uses one thread, if you request /sleep and then /, the / request should block until the /sleep one finishes. If it uses multiple threads, the / request should return without waiting for the /sleep one. Currently it blocks. Rearranging pool.scoped(|scope|{ and the loop fixes it.

This also seems to fix the bug where if the handler panics the whole server goes down 👍

@scriptjunkie
Copy link

I have tested the following, and can confirm it works:


    pub fn listen_on_socket(&self, listener: TcpListener) -> ! {
        const READ_TIMEOUT_MS: u64 = 20;
        let num_threads = self.pool_size();
        let mut pool = Pool::new(num_threads);
        let mut incoming = listener.incoming();

        pool.scoped(|scope| {
			loop {
				// Incoming is an endless iterator, so it's okay to unwrap on it.
				let stream = incoming.next().unwrap();
				let stream = stream.expect("Error handling TCP stream.");

				stream
                .set_read_timeout(Some(Duration::from_millis(READ_TIMEOUT_MS)))
                .expect("FATAL: Couldn't set read timeout on socket");

                scope.execute(|| {
                    self.handle_connection(stream).map_err(|e| match e{
							Error::Io(err) => println!("Error handling connection {}", err),
							_ => {}
						}
					);
                });
			}
        })
    }

this also prevents a handler panic from bringing a thread down. (otherwise, it might seem like it continues to work, but I think you have still killed one of the threads in the thread pool)

chernomor pushed a commit to chernomor/simple-server that referenced this issue Dec 27, 2019
chernomor pushed a commit to chernomor/simple-server that referenced this issue Dec 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants