This repository was archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Graceful shutdown for the task manager #6654
Merged
Merged
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
a245e96
Initial commit
cecton fe1c372
Move task_manager.rs to mod.rs
cecton 163501a
Graceful shutdown for the task manager
cecton cf228c0
Await all background task JoinHandle at the same time
cecton 551268b
Add tests
cecton b3c0648
Make future() wait also for exit signal + fix essential task failed
cecton 2855ada
add comments for non-obvious code
cecton db34d96
Use clean_shutdown() in sc-cli
cecton 2dcd0b3
Adapt code and upgrade tokio in sc-cli
cecton 42333f4
cleanup spacing in doc
cecton 1198324
Add license
cecton 56c8139
I guess actually running the clean shutdown would be a good idea
cecton ef3a054
fix tests
cecton 6f656cf
Merge remote-tracking branch 'origin/master' into cecton-async-gracef…
gnunicorn 4e6b8d2
Update client/cli/src/runner.rs
cecton 5dbe179
Improve error logging
cecton c133c59
disable other tests (can't reproduce on my machine)
cecton 1fb6481
Revert "disable other tests (can't reproduce on my machine)"
cecton 502aba4
It is possible that the tasks are ended first
cecton 1b91a8c
Revert "It is possible that the tasks are ended first"
cecton ee5e13c
Use single threaded scheduler for more predictability
cecton 4e15214
enable_time
cecton fbcefa4
Revert "enable_time"
cecton 23b642a
Revert "Use single threaded scheduler for more predictability"
cecton 5b5becb
Revert "Revert "It is possible that the tasks are ended first""
cecton bc431b6
This cannot be verified either with a threaded pool
cecton aaf038c
Merge commit 1be02953d4eb521ac1d40e55c71b44e2031ac105 (no conflict)
cecton 2a1a2ac
Merge commit 47be8d939148b0cb0d98d9ba132f082829c12e04 (no conflict)
cecton c079e31
Merge commit 5c43b2bebb331ebeaac5b6e21778203b1c73aa83 (no conflict)
cecton fbcb752
Merge commit cd67889e08b8f79af00c159b35f126c1cb106dda (no conflict)
cecton e4ad84a
Merge commit 86f85949329f0b27b56c41cd02ae30413e62fa5e (conflicts)
cecton b5e5fe2
Apply suggestions from code review
cecton 5fd98a6
Merge commit e3bb2cea3187fca77fd892becd35294a6cd7daeb (no conflict)
cecton File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add tests
- Loading branch information
commit 551268b387a8d6c802e538697c4d2b2fe0cee4d4
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| use crate::config::TaskExecutor; | ||
| use crate::task_manager::TaskManager; | ||
| use futures::future::FutureExt; | ||
| use parking_lot::Mutex; | ||
| use std::any::Any; | ||
| use std::sync::Arc; | ||
| use std::time::Duration; | ||
|
|
||
| #[derive(Clone)] | ||
| struct DropTester(Arc<Mutex<usize>>); | ||
|
|
||
| struct DropTesterRef(DropTester); | ||
|
|
||
| impl DropTester { | ||
| fn new() -> DropTester { | ||
| DropTester(Arc::new(Mutex::new(0))) | ||
| } | ||
|
|
||
| fn new_ref(&self) -> DropTesterRef { | ||
| *self.0.lock() += 1; | ||
| DropTesterRef(self.clone()) | ||
| } | ||
|
|
||
| fn assert_eq(&self, n: usize) { | ||
| assert_eq!(*self.0.lock(), n, "unexpected value for drop tester"); | ||
| } | ||
| } | ||
|
|
||
| impl Drop for DropTesterRef { | ||
| fn drop(&mut self) { | ||
| *(self.0).0.lock() -= 1; | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn ensure_drop_tester_working() { | ||
| let drop_tester = DropTester::new(); | ||
| drop_tester.assert_eq(0); | ||
| let drop_tester_ref_1 = drop_tester.new_ref(); | ||
| drop_tester.assert_eq(1); | ||
| let drop_tester_ref_2 = drop_tester.new_ref(); | ||
| drop_tester.assert_eq(2); | ||
| drop(drop_tester_ref_1); | ||
| drop_tester.assert_eq(1); | ||
| drop(drop_tester_ref_2); | ||
| drop_tester.assert_eq(0); | ||
| } | ||
|
|
||
| async fn run_background_task(_keep_alive: impl Any) { | ||
| loop { | ||
| tokio::time::delay_for(Duration::from_secs(1)).await; | ||
| } | ||
| } | ||
|
|
||
| async fn run_background_task_blocking(duration: Duration, _keep_alive: impl Any) { | ||
| loop { | ||
| // block for X sec (not interruptible) | ||
| std::thread::sleep(duration); | ||
| // await for 1 sec (interruptible) | ||
| tokio::time::delay_for(Duration::from_secs(1)).await; | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn ensure_futures_are_awaited_on_shutdown() { | ||
| let mut runtime = tokio::runtime::Runtime::new().unwrap(); | ||
| let handle = runtime.handle().clone(); | ||
| let task_executor: TaskExecutor = (move |future, _| handle.spawn(future).map(|_| ())).into(); | ||
|
|
||
| let task_manager = TaskManager::new(task_executor, None).unwrap(); | ||
| let spawn_handle = task_manager.spawn_handle(); | ||
| let drop_tester = DropTester::new(); | ||
| spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref())); | ||
| spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref())); | ||
| drop_tester.assert_eq(2); | ||
| // allow the tasks to even start | ||
| runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await }); | ||
| drop_tester.assert_eq(2); | ||
| runtime.block_on(task_manager.clean_shutdown()); | ||
| drop_tester.assert_eq(0); | ||
| } | ||
|
|
||
| #[test] | ||
| fn ensure_keep_alive_during_shutdown() { | ||
| let mut runtime = tokio::runtime::Runtime::new().unwrap(); | ||
| let handle = runtime.handle().clone(); | ||
| let task_executor: TaskExecutor = (move |future, _| handle.spawn(future).map(|_| ())).into(); | ||
|
|
||
| let mut task_manager = TaskManager::new(task_executor, None).unwrap(); | ||
| let spawn_handle = task_manager.spawn_handle(); | ||
| let drop_tester = DropTester::new(); | ||
| task_manager.keep_alive(drop_tester.new_ref()); | ||
| spawn_handle.spawn("task1", run_background_task(())); | ||
| drop_tester.assert_eq(1); | ||
| // allow the tasks to even start | ||
| runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await }); | ||
| drop_tester.assert_eq(1); | ||
| runtime.block_on(task_manager.clean_shutdown()); | ||
| drop_tester.assert_eq(0); | ||
| } | ||
|
|
||
| #[test] | ||
| fn ensure_blocking_futures_are_awaited_on_shutdown() { | ||
| let mut runtime = tokio::runtime::Runtime::new().unwrap(); | ||
| let handle = runtime.handle().clone(); | ||
| let task_executor: TaskExecutor = (move |future, _| handle.spawn(future).map(|_| ())).into(); | ||
|
|
||
| let task_manager = TaskManager::new(task_executor, None).unwrap(); | ||
| let spawn_handle = task_manager.spawn_handle(); | ||
| let drop_tester = DropTester::new(); | ||
| spawn_handle.spawn( | ||
| "task1", | ||
| run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), | ||
| ); | ||
| spawn_handle.spawn( | ||
| "task2", | ||
| run_background_task_blocking(Duration::from_secs(3), drop_tester.new_ref()), | ||
| ); | ||
| drop_tester.assert_eq(2); | ||
| // allow the tasks to even start | ||
| runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await }); | ||
| drop_tester.assert_eq(2); | ||
| runtime.block_on(task_manager.clean_shutdown()); | ||
| drop_tester.assert_eq(0); | ||
| } | ||
|
|
||
| #[test] | ||
| fn ensure_no_task_can_be_spawn_after_terminate() { | ||
| let mut runtime = tokio::runtime::Runtime::new().unwrap(); | ||
| let handle = runtime.handle().clone(); | ||
| let task_executor: TaskExecutor = (move |future, _| handle.spawn(future).map(|_| ())).into(); | ||
|
|
||
| let mut task_manager = TaskManager::new(task_executor, None).unwrap(); | ||
| let spawn_handle = task_manager.spawn_handle(); | ||
| let drop_tester = DropTester::new(); | ||
| spawn_handle.spawn("task1", run_background_task(drop_tester.new_ref())); | ||
| spawn_handle.spawn("task2", run_background_task(drop_tester.new_ref())); | ||
| drop_tester.assert_eq(2); | ||
| // allow the tasks to even start | ||
| runtime.block_on(async { tokio::time::delay_for(Duration::from_secs(1)).await }); | ||
| drop_tester.assert_eq(2); | ||
| task_manager.terminate(); | ||
| spawn_handle.spawn("task3", run_background_task(drop_tester.new_ref())); | ||
| // NOTE: task3 will not increase the count because it has been ignored | ||
| drop_tester.assert_eq(2); | ||
| runtime.block_on(task_manager.clean_shutdown()); | ||
| drop_tester.assert_eq(0); | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.