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

Cookbook #23

Open
carllerche opened this issue Oct 2, 2018 · 18 comments
Open

Cookbook #23

carllerche opened this issue Oct 2, 2018 · 18 comments
Labels
guide Relates to an existing or missing guide.

Comments

@carllerche
Copy link
Member

carllerche commented Oct 2, 2018

What kinds of things should be in the cookbook?

Prior discussion

@eminence
Copy link

eminence commented Oct 3, 2018

How do I hook up timers to the networking stack? For example, how do I send a UDP packet every 5 seconds?

Getting a a timer set-up is really easy:

    let interval = Interval::new_interval(Duration::from_secs(5));

    let task = interval.map_err(|e| ()).for_each(|_| {
        println!("Timer has fired");
        future::done(Ok(()))
    });

    tokio::run(task);

Sending a single message on a socket is pretty easy, too

    let local = "0.0.0.0:12345".parse().unwrap();
    let target = "10.11.12.13:12345".parse().unwrap();

    let socket = UdpSocket::bind(&local).unwrap();

    let task = socket.send_dgram("hello".as_bytes(), &target).then(|r| {
        if let Ok(s) = r {
            println!("Successfully send bytes to socket");
        // could send another message using `s` now if we wanted
        } else {
            println!("Failed to send bytes");
        }
        future::done(Ok(()))
    });

    tokio::run(task);

But how do I combine them? The hard part seems to be that send_dgram takes ownership of the socket for a little while, which prevents the socket from being owned by the for-each closure.

@eminence
Copy link

eminence commented Oct 3, 2018

What's the pattern for taking "events" from multiple sources and handling them all in the same handler? For example, waiting for network data, waiting for keyboard input, and a timer?

My guess is that you would take your streams and map them all to the same wrapper type (probably an enum), and then use Stream::select to merge them all into a single Stream

@carllerche carllerche added the guide Relates to an existing or missing guide. label Oct 3, 2018
@carllerche
Copy link
Member Author

Ok, I seeded the cookbook outline here.

Please provide additional items via PR 👍

@eminence
Copy link

eminence commented Oct 3, 2018

Could you please add another small seed that shows the structure for providing actual cookbook entries? (I mean the actual example code, not just the description of the cookbook entry). Should we just create new .md files in a new cookbook/ sub-directory?

@carllerche
Copy link
Member Author

I would probably follow the structure of https://rust-lang-nursery.github.io/rust-cookbook/.

A new folder for cookbook and one md file per category with all the examples for that category on the same page.

If you are trying to get started and creating the structure is not something you want to do in the PR, just post a gist here and I can use that to setup the structure.

@rrichardson
Copy link

If we could organize a group effort in the Tokio channels, I bet we could get spans of code from dozens of existing projects that demonstrate these tasks.

@carllerche
Copy link
Member Author

@rrichardson sure, however you want to do it 👍

@ghost
Copy link

ghost commented Oct 4, 2018

A topic that I'm interested in is client connection pooling.

I've been thinking about toying around with the Cassandra database protocol that communicates over TCP and supports asynchronous connections. There can be multiple connections to multiple DB servers and each connection can be used to send multiple requests (each request is assigned a stream ID that will also be added to the response, so that the driver knows what query to complete). Maybe a high level concept of that description could be implemented?

That would be a pretty involved example and maybe it's not suitable for this cookbook, but I just thought I'd spit it out here.

@carllerche
Copy link
Member Author

A connection pool is definitely a good example... I wonder if it should be included as a dedicated page in the Transports section.

Also, maybe the cookbook should link to examples throughout the guide as well in cases where the example is more complex.

@ghost
Copy link

ghost commented Oct 4, 2018

The connection pool example would be a great addition to the transports section as it shows how to implement a more complex client protocol implementation. Then the transports section has both client and server protocol implementation examples covered. IMO it's also refreshing to see stuff besides HTTP.

@rrichardson
Copy link

Below is a wish-list that I've distilled from https://github.com/tokio-rs/doc-push/blob/master/outline/cookbook.md for quick reference. I'll update it with source/gist links as we find them.

  1. Spawn a task to work in the background and check the results.
  2. Shutting down: monitor for signals, shutdown sockets, background tasks, and the reactor. Setting a timer for non-graceful override.
  3. Multiple tasks mutating a single Hash Map
  4. Enqueuing messages to be sent by another task.
  5. Launch a pool for CPU intensive tasks and check the results
  6. Send a file over a TcpStream
  7. Return different future/stream types from different branches in a function using Box
  8. Return different future/stream types from different branches using Either or similar.
  9. Handle multiple Event types from multiple stream types using type unification and select()
  10. Use DNS to resolve a host and then connect
  11. Read and write via stdin and stdout
  12. Spawn, Manage, and communicate with child processes.
  13. Send a TCP/UDP packet every 5 seconds.
  14. Listen and timeout on receiving a heartbeat over TCP/UDP
  15. Limit/kill a stream by duration (e.g 30 seconds)
  16. Limit/kill a stream by number of messages (e.g. using take)
  17. Handle errors in a stream using a transport decorator

@carllerche
Copy link
Member Author

@rrichardson very nice list

@leshow
Copy link

leshow commented Oct 5, 2018

A fairly simple one, but something I ran into: spawning tasks on the current thread only (without using the default runtime), lending handle references to spawn tasks on the same thread.

@jgrund
Copy link

jgrund commented Oct 24, 2018

A full example of DelayQueue with usage.

@kosta
Copy link

kosta commented Nov 20, 2018

I would like cookbook recipe for limiting the number of in-flight requests.

E.g. when I'm feeding a channel from a separate thread that is read from tokio as a Stream; and only want n Futures to be in-flight at a time. Desired behaviour would be that limiting reading from the stream would put backpressure on the "feeding" thread.

@carllerche
Copy link
Member Author

Another example:

Download files using an HTTP client in parallel and write them to files.

@rrichardson
Copy link

Download files using an HTTP client in parallel and write them to files.

I just wrote this exact thing for work. I could probably sanitize it and throw it in.

On a side note: What is the scope of this cookbook now? Async/Await and Tokio v0.2+ ?

@carllerche
Copy link
Member Author

Yes, async/await and 0.2 :) I am hoping to get this done around the time the final lands... 3 months maybe, 6 months definitely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
guide Relates to an existing or missing guide.
Projects
None yet
Development

No branches or pull requests

6 participants