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 · 15 comments

Comments

Projects
None yet
7 participants
@carllerche
Member

carllerche commented Oct 2, 2018

What kinds of things should be in the cookbook?

Prior discussion

@eminence

This comment has been minimized.

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

This comment has been minimized.

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 label Oct 3, 2018

@carllerche

This comment has been minimized.

Member

carllerche commented Oct 3, 2018

Ok, I seeded the cookbook outline here.

Please provide additional items via PR 👍

@eminence

This comment has been minimized.

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

This comment has been minimized.

Member

carllerche commented Oct 3, 2018

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

This comment has been minimized.

rrichardson commented Oct 4, 2018

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

This comment has been minimized.

Member

carllerche commented Oct 4, 2018

@rrichardson sure, however you want to do it 👍

@kadfak

This comment has been minimized.

kadfak 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

This comment has been minimized.

Member

carllerche commented Oct 4, 2018

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.

@kadfak

This comment has been minimized.

kadfak 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

This comment has been minimized.

rrichardson commented Oct 4, 2018

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

This comment has been minimized.

Member

carllerche commented Oct 4, 2018

@rrichardson very nice list

@leshow

This comment has been minimized.

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

This comment has been minimized.

jgrund commented Oct 24, 2018

A full example of DelayQueue with usage.

@kosta

This comment has been minimized.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment