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

Reduce lifetime requirements of serve. #1669

Open
Jezza opened this issue Oct 9, 2018 · 8 comments
Open

Reduce lifetime requirements of serve. #1669

Jezza opened this issue Oct 9, 2018 · 8 comments
Labels
A-server Area: server. B-upstream Blocked: needs a change in a dependency or the compiler.

Comments

@Jezza
Copy link

Jezza commented Oct 9, 2018

Currently the NewService trait, and a lot of the other parameters for serve require a 'static lifetime.
I'm a bit of a Rust rookie, but wouldn't it be better to tie it to the server itself?

As it stands, there's no safe way to do something like:
(Where self is some managed state)

fn start(self, port: u16) {
	let addr = ([127, 0, 0, 1], port).into();

	let service_factory =
		|| service_fn(|req| handle_incoming(&self, req));

	let server = Server::bind(&addr)
		.serve(service_factory)
		.map_err(|e| eprintln!("Server error: {}", e));

	hyper::rt::run(server);
}

I can't take a reference to self, because the lifetime is static.
Even though, the server is started on the next line, and it blocks.
So, once it gets to the end of this method, the server would have already stopped.

@seanmonstar
Copy link
Member

Part of the requirement for 'static is because the future from the Service is going to be spawned on an executor which can potentially be a thread pool, so the future can't have any references since it might live on another thread.

@Jezza
Copy link
Author

Jezza commented Oct 9, 2018

I understand, but doesn't tokio::run block until the runtime itself is shutdown, meaning self won't be dropped until the end of the method?

Hm, is there a safe way to hand out a reference, because the application itself isn't dropped until after the runtime is killed?
Preferably, without a runtime cost...

@seanmonstar
Copy link
Member

Yea, I see what you mean. Maybe something could be done in tokio. The function hyper::rt::run just defers to tokio::run internally.

@seanmonstar seanmonstar added the B-upstream Blocked: needs a change in a dependency or the compiler. label Oct 17, 2018
@seanmonstar seanmonstar added the A-server Area: server. label Jan 24, 2019
@rustonaut
Copy link

As far as I know the problem of tokio::run is the same as std::thread::spawn, so to support it some think like scoped threads are needed. But likely far more complex (to verify) as it needs to work with all the aspects of the tokio event loop/thread pool.

Through I think at last theoretically tokio::run and similar "block until future and futures spawned by future are done" operations could be non 'static it would require more unsafe code in tokio, so I'm not sure if there are any plans to support it.

Anyway I don't think this will be possible anytime soon.

@peku33
Copy link

peku33 commented Oct 24, 2019

Any update on this?
Isn't it really safe for service to live just as long as the server itself?
It's really unpleasant to create a server that passes requests to &dyn trait.

@ghost
Copy link

ghost commented May 17, 2020

this is driving me crazy. is there a way to do this. I have a database client and I want to use it but this doesn't let me. I tried Box::leak, mem::transmute. Nothing is working.

@rustonaut
Copy link

I took a look at things tokio provides for handling non 'static futures so here is a small overview:

block_on

Appears in three places Runtime::block_on, Handle::block_on, LocalSet::block_on.

Doesn't require neither of 'static, Send and Sync.

Only returns from the function call once the future completed.

Must drive the future exclusively on the current thread. As neither Send nor Sync are required. Through for some reasons only LocalSet::block_on documents this and Runtime::block_on and Handle::block_on doesn't which has me a bit worried.

Drawbacks

  • This function can not be called in a asynchronous execution context.
  • No proper usage of the thread pool as futures are not Send.
  • Wrt. to LocalSet block_in_place can not be used in a future which is driven using block_on. (Which might be surprising but LocalSet allows driving multiple futures on the current thread until completion which can lead to very surprising dead-locks for some usages of block_in_place. I haven't tried out what happens if block_in_place is used in the other block_on functions. But it should be fine as the other block_on functions only run one future on the given thread (as they don't support spawn_local).

run_until

Only supported by LocalSet.

Doesn't require neither of 'static, Send and Sync.

Is similar to block_on but is a async fn. So it's a block_on for usage in a async context.

Only "continues" the calling async fn when the future completes.

Drawbacks

  • No proper usage of the thread pool as futures are not Send. But allows polling multiple futures on the current thread.
  • I don't know if block_in_place can be used. Probably not as it's sharing the local set with other futures spawned with spawn_local

@rustonaut
Copy link

Sadly there is no single method which allows non 'static Future with Send and which "properly" used the whole thread pool and in turn can properly support block_in_place. But this is also known to be a very hard problem. (From the removed scoped threads functionality).

It is possible to combine futures with Sync, work stealing and a thread pool with thread bound futures using LocalSet (similar to how actix does it). It wouldn't be exactly a solution for the problem mentioned here and it has a major problem. The futures most likely to call block_in_place, i.e. where it's most useful are also the which would run in a LocalSet where it doesn't work. :(

But as run_until has shown async fn's allow us new possibilities. So maybe we can find a way to have Send + non 'static + work stealing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-server Area: server. B-upstream Blocked: needs a change in a dependency or the compiler.
Projects
None yet
Development

No branches or pull requests

4 participants