Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Replace Service's future impl by not-self-consuming method #6306

Closed
wants to merge 9 commits into from

Conversation

cecton
Copy link
Contributor

@cecton cecton commented Jun 9, 2020

Problem it tries to fix

When the Service needs to be shutdown, run_service_until_exit does:

  1. extracts the telemetry and the base_path from the Service
  2. drop the Service
  3. drop the tokio runtime which will wait for all the tasks to finish

The reason why we do this in this particular order is because dropping the service will trigger the drop of the task_manager which will trigger the task's exit.

But this is annoying because it means we need to keep references on things that we don't want to be deleted during the tear down (telemetry and base_path).

A better approach would be to:

  1. signal termination (all tasks must finish)
  2. drop the tokio runtime

This would make sure that the things that must not be dropped before the tokio runtime are kept.

Proposed solution

  1. add a terminate() method on the task_manager and on the Service to signal all the task to finish
  2. add a future() method on Service that will not consume self, thus not drop the service when the future is dropped
  3. remove the Future impl on Service as you most likely don't want to lose your Service after a failure

I think the point 2. & 3. are not required but it makes more sense for the API.

Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
@cecton cecton requested review from tomaka, bkchr and arkpar June 9, 2020 10:01
@cecton cecton self-assigned this Jun 9, 2020
@parity-cla-bot
Copy link

It looks like @cecton signed our Contributor License Agreement. 👍

Many thanks,

Parity Technologies CLA Bot

@@ -304,7 +302,6 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
let addr = node_config.network.listen_addresses.iter().next().unwrap().clone();
let service = SyncService::from(light(node_config).expect("Error creating test node service"));

executor.spawn(service.clone().map_err(|_| ()));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh I'm not sure why those tasks are spawn because the Future impl Service is just waiting indefinitely and stops if there is an essential task failing. But since this is spawn like a background process, nobody is doing anything with the result anyway. Will see if it breaks on the CI

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Service used to properly own the tasks that it runs, and process them manually if no executor is available, rather than always spawning these tasks in the background.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That explains everything

@cecton cecton requested a review from danforbes June 9, 2020 10:13
@tomaka
Copy link
Contributor

tomaka commented Jun 9, 2020

I guess this is all debatable, but it was initially designed this way because good programming practices consist in stopping or killing stuff when destructors are being run, rather than having to call a terminate method.

@tomaka
Copy link
Contributor

tomaka commented Jun 9, 2020

In my opinion we have the choice between two approaches: either make the Service properly own everything it runs and properly hide implementation details, or turn it into a dummy struct with public fields which acts as the success value of a building function that spawns a bunch of tasks.

Having a Service whose constructor spawns tasks, but which can then be destroyed without these tasks stopping, is a middle ground that doesn't really make sense to me.

@cecton cecton requested a review from gnunicorn June 9, 2020 11:18
@tomaka
Copy link
Contributor

tomaka commented Jun 9, 2020

I don't really have a clear opinion on this PR or how the Service should be designed in particular, but I'm of the opinion that we should have a clear design to follow rather than making incremental changes that seem to go a bit in all directions.

@cecton
Copy link
Contributor Author

cecton commented Jun 9, 2020

🤔 it makes a lot more sense to me now.

I guess in the current evolution of the Service it would be logical to make the Service more dumb. The alternative to this would be for the Service to own the tokio runtime so it can stop the tasks properly when dropping. But I suppose that is something we don't want as it would limit how substrate can be used.

@gavofyork gavofyork added the A0-please_review Pull request needs code review. label Jun 10, 2020
@cecton cecton changed the title Replace Service's future impl by method not-self-consuming method Replace Service's future impl by not-self-consuming method Jun 10, 2020
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
Parent branch: origin/master
Forked at: 85cd556
@cecton
Copy link
Contributor Author

cecton commented Jun 30, 2020

Fixed by ec2ab79

@cecton cecton closed this Jun 30, 2020
@cecton cecton deleted the cecton-replace-service-future branch June 30, 2020 11:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants