Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/cargo/miette-7.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Finomnis committed Mar 30, 2024
2 parents 848fa1d + 81091d9 commit ae02fdd
Show file tree
Hide file tree
Showing 17 changed files with 385 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
name: Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: rustsec/[email protected]
with:
token: ${{ secrets.GITHUB_TOKEN }}
20 changes: 10 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- x86_64-unknown-linux-gnu
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install cross
uses: taiki-e/install-action@cross
Expand All @@ -40,7 +40,7 @@ jobs:
RUSTFLAGS: "-D warnings"
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
Expand All @@ -58,7 +58,7 @@ jobs:
RUSTFLAGS: "-D warnings"
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install cargo-binstall
uses: taiki-e/install-action@cargo-binstall
Expand All @@ -77,7 +77,7 @@ jobs:
needs: [lints, docs]
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Check semver
uses: obi1kenobi/cargo-semver-checks-action@v2

Expand All @@ -87,7 +87,7 @@ jobs:
needs: [lints, docs]
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
Expand All @@ -111,7 +111,7 @@ jobs:
RUSTFLAGS: "-D warnings"
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
Expand Down Expand Up @@ -142,7 +142,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
Expand All @@ -160,7 +160,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
Expand All @@ -176,7 +176,7 @@ jobs:
needs: [lints, docs]
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install llvm
# Required to resolve symbols in sanitizer output
Expand Down Expand Up @@ -208,7 +208,7 @@ jobs:
needs: [build, test, msrv, lints, docs, leaks, semver, min-versions, min-versions-msrv]
steps:
- name: Checkout sources
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@ jobs:
with:
components: llvm-tools-preview
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
#- uses: Swatinem/rust-cache@v1
- name: Compute Coverage
run:
cargo llvm-cov --all-features --workspace --ignore-filename-regex tests.rs --codecov --output-path codecov.json
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
files: codecov.json
fail_ci_if_error: true
- name: Archive code coverage results
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: code-coverage-report
path: codecov.json
6 changes: 3 additions & 3 deletions .github/workflows/rust-clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ jobs:
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy

- name: Install sarif tools
uses: taiki-e/install-action@v1
uses: taiki-e/install-action@v2
with:
tool: clippy-sarif,sarif-fmt

Expand All @@ -49,7 +49,7 @@ jobs:
continue-on-error: true

- name: Upload analysis results to GitHub
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: rust-clippy-results.sarif
wait-for-processing: true
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "tokio-graceful-shutdown"
authors = ["Finomnis <[email protected]>"]
version = "0.14.2"
version = "0.14.3"
edition = "2021"
rust-version = "1.70"
license = "MIT OR Apache-2.0"
Expand Down
125 changes: 125 additions & 0 deletions examples/19_sequential_shutdown.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//! This example demonstrates how multiple subsystems could be shut down sequentially.
//!
//! When a shutdown gets triggered (via Ctrl+C), Nested1 will shutdown first,
//! followed by Nested2 and Nested3. Only once the previous subsystem is finished shutting down,
//! the next subsystem will follow.
use miette::Result;
use tokio::time::{sleep, Duration};
use tokio_graceful_shutdown::{
FutureExt, SubsystemBuilder, SubsystemFinishedFuture, SubsystemHandle, Toplevel,
};

async fn counter(id: &str) {
let mut i = 0;
loop {
tracing::info!("{id}: {i}");
i += 1;
sleep(Duration::from_millis(50)).await;
}
}

async fn nested1(subsys: SubsystemHandle) -> Result<()> {
tracing::info!("Nested1 started.");
if counter("Nested1").cancel_on_shutdown(&subsys).await.is_ok() {
tracing::info!("Nested1 counter finished.");
} else {
tracing::info!("Nested1 shutting down ...");
sleep(Duration::from_millis(200)).await;
}
subsys.on_shutdown_requested().await;
tracing::info!("Nested1 stopped.");
Ok(())
}

async fn nested2(subsys: SubsystemHandle, nested1_finished: SubsystemFinishedFuture) -> Result<()> {
// Create a future that triggers once nested1 is finished **and** a shutdown is requested
let shutdown = {
let shutdown_requested = subsys.on_shutdown_requested();
async move {
tokio::join!(shutdown_requested, nested1_finished);
}
};

tracing::info!("Nested2 started.");
tokio::select! {
_ = shutdown => {
tracing::info!("Nested2 shutting down ...");
sleep(Duration::from_millis(200)).await;
}
_ = counter("Nested2") => {
tracing::info!("Nested2 counter finished.");
}
}

tracing::info!("Nested2 stopped.");
Ok(())
}

async fn nested3(subsys: SubsystemHandle, nested2_finished: SubsystemFinishedFuture) -> Result<()> {
// Create a future that triggers once nested2 is finished **and** a shutdown is requested
let shutdown = {
// This is an alternative to `on_shutdown_requested()` (as shown in nested2).
// Use this if `on_shutdown_requested()` gives you lifetime issues.
let cancellation_token = subsys.create_cancellation_token();
async move {
tokio::join!(cancellation_token.cancelled(), nested2_finished);
}
};

tracing::info!("Nested3 started.");
tokio::select! {
_ = shutdown => {
tracing::info!("Nested3 shutting down ...");
sleep(Duration::from_millis(200)).await;
}
_ = counter("Nested3") => {
tracing::info!("Nested3 counter finished.");
}
}

tracing::info!("Nested3 stopped.");
Ok(())
}

async fn root(subsys: SubsystemHandle) -> Result<()> {
tracing::info!("Root started.");

tracing::info!("Starting nested subsystems ...");
let nested1 = subsys.start(SubsystemBuilder::new("Nested1", nested1));
let nested1_finished = nested1.finished();
let nested2 = subsys.start(SubsystemBuilder::new("Nested2", |s| {
nested2(s, nested1_finished)
}));
let nested2_finished = nested2.finished();
subsys.start(SubsystemBuilder::new("Nested3", |s| {
nested3(s, nested2_finished)
}));
tracing::info!("Nested subsystems started.");

// Wait for all children to finish shutting down.
subsys.wait_for_children().await;

tracing::info!("All children finished, stopping Root ...");
sleep(Duration::from_millis(200)).await;
tracing::info!("Root stopped.");

Ok(())
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {
// Init logging
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();

// Setup and execute subsystem tree
Toplevel::new(|s| async move {
s.start(SubsystemBuilder::new("Root", root));
})
.catch_signals()
.handle_shutdown_requests(Duration::from_millis(1000))
.await
.map_err(Into::into)
}
83 changes: 83 additions & 0 deletions examples/20_orchestrated_shutdown_order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! This example demonstrates how a parent subsystem could orchestrate
//! the shutdown order of its children manually.
//!
//! This is done by spawning the children in 'detached' mode to prevent
//! that the shutdown signal gets passed to the children.
//! Then, the parent calls `initialize_shutdown` on each child manually.
use miette::Result;
use tokio::time::{sleep, Duration};
use tokio_graceful_shutdown::{FutureExt, SubsystemBuilder, SubsystemHandle, Toplevel};

async fn counter(id: &str) {
let mut i = 0;
loop {
tracing::info!("{id}: {i}");
i += 1;
sleep(Duration::from_millis(50)).await;
}
}

async fn child(name: &str, subsys: SubsystemHandle) -> Result<()> {
tracing::info!("{name} started.");
if counter(name).cancel_on_shutdown(&subsys).await.is_ok() {
tracing::info!("{name} counter finished.");
} else {
tracing::info!("{name} shutting down ...");
sleep(Duration::from_millis(200)).await;
}
subsys.on_shutdown_requested().await;
tracing::info!("{name} stopped.");
Ok(())
}

async fn parent(subsys: SubsystemHandle) -> Result<()> {
tracing::info!("Parent started.");

tracing::info!("Starting detached nested subsystems ...");
let nested1 =
subsys.start(SubsystemBuilder::new("Nested1", |s| child("Nested1", s)).detached());
let nested2 =
subsys.start(SubsystemBuilder::new("Nested2", |s| child("Nested2", s)).detached());
let nested3 =
subsys.start(SubsystemBuilder::new("Nested3", |s| child("Nested3", s)).detached());
tracing::info!("Nested subsystems started.");

// Wait for the shutdown to happen
subsys.on_shutdown_requested().await;

// Shut down children sequentially. As they are detached, they will not shutdown on their own,
// but need to be shut down manually via `initiate_shutdown`.
tracing::info!("Initiating Nested1 shutdown ...");
nested1.initiate_shutdown();
nested1.join().await?;
tracing::info!("Initiating Nested2 shutdown ...");
nested2.initiate_shutdown();
nested2.join().await?;
tracing::info!("Initiating Nested3 shutdown ...");
nested3.initiate_shutdown();
nested3.join().await?;

tracing::info!("All children finished, stopping Root ...");
sleep(Duration::from_millis(200)).await;
tracing::info!("Root stopped.");

Ok(())
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {
// Init logging
tracing_subscriber::fmt()
.with_max_level(tracing::Level::TRACE)
.init();

// Setup and execute subsystem tree
Toplevel::new(|s| async move {
s.start(SubsystemBuilder::new("parent", parent));
})
.catch_signals()
.handle_shutdown_requests(Duration::from_millis(1000))
.await
.map_err(Into::into)
}
2 changes: 1 addition & 1 deletion src/future_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use pin_project_lite::pin_project;
use tokio_util::sync::WaitForCancellationFuture;

pin_project! {
/// A Future that is resolved once the corresponding task is finished
/// A future that is resolved once the corresponding task is finished
/// or a shutdown is initiated.
#[must_use = "futures do nothing unless polled"]
pub struct CancelOnShutdownFuture<'a, T: std::future::Future>{
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,6 @@ pub use future_ext::FutureExt;
pub use into_subsystem::IntoSubsystem;
pub use subsystem::NestedSubsystem;
pub use subsystem::SubsystemBuilder;
pub use subsystem::SubsystemFinishedFuture;
pub use subsystem::SubsystemHandle;
pub use toplevel::Toplevel;
Loading

0 comments on commit ae02fdd

Please sign in to comment.