Skip to content

Creating Server with a Handle #1322

Closed
Closed
@seanmonstar

Description

@seanmonstar

I've put this off for a while claiming that it will be solved in tokio-proto, but I'm now leaning towards may as well fix it in hyper, if a generic way appears in the future, no harm done. So, on to the proposal:


I hinted at a possible solution earlier in another issue, and I think a solution is probably similar: Add a way to combine an Http, Service, TcpListener, and Handle into a impl Future.

Proposed API

  • Http
    • pub fn bind_handle<S>(&self, addr: &SocketAddr, new_service: S, handle: &Handle) -> Server
  • Server
    • pub fn shutdown_signal<F>(&mut self, signal: F) -> &mut Self
    • impl Future for Server

Usage

// Spawn 2 servers on the same Core
let mut core = Core::new()?;
let handle = core.handle();

let srv1 = Http::new()
    .bind_handle(addr1, new_service1, &handle);

let srv2 = Http::new()
    .bind_handle(addr2, new_service2, &handle);

handle.spawn(srv1);
handle.spawn(srv2);
core.run(futures::future::empty())?;
// Spawn a Server with a Client
let mut core = Core::new()?;
let handle = core.handle();

let client = Client::new(&handle);
let server = Http::new()
    .bind_handle(addr, new_service(client), &handle);
handle.spawn(server);

core.run(futures::future::empty())?;
// Spawn a Server and still get graceful shutdown
let mut core = Core::new()?;
let handle = core.handle();

// send on tx to shutdown server future
let (tx, rx) = oneshot::channel();

let client = Client::new(&handle);
let mut server = Http::new()
    .bind_handle(addr, new_service(client), &handle);
server.shutdown_signal(rx);

// can even just run server directly
core.run(server)?;

Implementation

This proposal is reusing the Server type, which already exists in a form that owns a Core. Internally, it can just change its field to an enum of 2 variants, 1 with a Core, and the other with a Handle. It should be able to use the majority of the same code in both cases.

It might be tricky that you can create a Server using Http::bind, which owns a Core, and then you can send that Server into another Core, calling handle.spawn(server). If you were to do that, the impl Future for Server could make the outer Core lock up, since an implementation might decide to call core.run() on its inner Core.

To prevent that mistake, the impl Future for Server should probably panic if the Server owns a Core, and not a Handle, with a nice message explaining don't do that.

/cc #1075 #1263

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-serverArea: server.C-featureCategory: feature. This is adding a new feature.E-mediumEffort: medium. Some knowledge of how hyper internal works would be useful.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions