Compare commits
17 Commits
v0.5.0
...
610aa3d0b7
Author | SHA1 | Date | |
---|---|---|---|
|
610aa3d0b7 | ||
f049750e4c | |||
0b5f19fc77 | |||
14eabdbe82 | |||
ea568449fe | |||
6ec3a6031e | |||
0f8fd2343e | |||
12c00941b5 | |||
72755f9cf1 | |||
ae0b8b703e
|
|||
3c3f638004 | |||
ea5287152c
|
|||
14371cdfd7 | |||
3a1b1673ef | |||
89cbae24d0 | |||
7c1b317d08
|
|||
1fec4e3708
|
32
CHANGELOG.md
32
CHANGELOG.md
@@ -6,6 +6,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.7.2] - 2024-12-14
|
||||
|
||||
### Fixed
|
||||
- *(deps)* update rust crate thiserror to v2.0.7 (#20)
|
||||
- *(deps)* update rust crate thiserror to v2.0.6 (#19)
|
||||
- *(deps)* update rust crate thiserror to v2.0.5 (#18)
|
||||
- *(deps)* update rust crate tokio-util to v0.7.13 (#17)
|
||||
|
||||
### Other
|
||||
- *(deps)* update all dependencies (#16)
|
||||
- *(deps)* update rust crate tracing-subscriber to v0.3.19 (#15)
|
||||
- *(deps)* update rust crate tracing to v0.1.41 (#13)
|
||||
|
||||
## [0.7.1] - 2024-11-24
|
||||
|
||||
### Fixed
|
||||
- make sure to close on final
|
||||
|
||||
## [0.7.0] - 2024-11-24
|
||||
|
||||
### Added
|
||||
- actually bubble up errors
|
||||
|
||||
### Fixed
|
||||
- *(deps)* update rust crate thiserror to v2 (#9)
|
||||
|
||||
## [0.6.0] - 2024-11-23
|
||||
|
||||
### Added
|
||||
- adding test to make sure we can gracefully shutdown
|
||||
- make sure to close down properly
|
||||
|
||||
## [0.5.0] - 2024-11-19
|
||||
|
||||
### Added
|
||||
|
38
Cargo.lock
generated
38
Cargo.lock
generated
@@ -28,9 +28,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.93"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
@@ -266,7 +266,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "notmad"
|
||||
version = "0.4.0"
|
||||
version = "0.7.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -525,18 +525,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
version = "2.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
version = "2.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -555,9 +555,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.41.1"
|
||||
version = "1.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
|
||||
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -584,9 +584,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.12"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
|
||||
checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
@@ -597,9 +597,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.40"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
@@ -609,9 +609,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.27"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -620,9 +620,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
@@ -641,9 +641,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.18"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
|
@@ -3,7 +3,7 @@ members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.5.0"
|
||||
version = "0.7.2"
|
||||
|
||||
[workspace.dependencies]
|
||||
mad = { path = "crates/mad" }
|
||||
|
@@ -13,7 +13,7 @@ async-trait = "0.1.81"
|
||||
futures = "0.3.30"
|
||||
futures-util = "0.3.30"
|
||||
rand = "0.8.5"
|
||||
thiserror = "1.0.63"
|
||||
thiserror = "2.0.0"
|
||||
tokio.workspace = true
|
||||
tokio-util = "0.7.11"
|
||||
tracing.workspace = true
|
||||
|
@@ -133,6 +133,7 @@ impl Mad {
|
||||
let mut channels = Vec::new();
|
||||
let cancellation_token = CancellationToken::new();
|
||||
let job_cancellation = CancellationToken::new();
|
||||
let job_done = CancellationToken::new();
|
||||
|
||||
for comp in &self.components {
|
||||
let comp = comp.clone();
|
||||
@@ -154,21 +155,51 @@ impl Mad {
|
||||
res = comp.run(job_cancellation) => {
|
||||
error_tx.send(CompletionResult { res , name }).await
|
||||
}
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
error_tx.send(CompletionResult { res: Ok(()) , name }).await
|
||||
}
|
||||
_ = signal_unix_terminate() => {
|
||||
error_tx.send(CompletionResult { res: Ok(()) , name }).await
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tokio::spawn({
|
||||
let cancellation_token = cancellation_token;
|
||||
let job_done = job_done.child_token();
|
||||
|
||||
let wait_cancel = self.should_cancel;
|
||||
|
||||
async move {
|
||||
let should_cancel =
|
||||
|cancel: CancellationToken,
|
||||
global_cancel: CancellationToken,
|
||||
wait: Option<std::time::Duration>| async move {
|
||||
if let Some(cancel_wait) = wait {
|
||||
cancel.cancel();
|
||||
tokio::time::sleep(cancel_wait).await;
|
||||
global_cancel.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
tokio::select! {
|
||||
_ = cancellation_token.cancelled() => {
|
||||
job_cancellation.cancel();
|
||||
}
|
||||
_ = job_done.cancelled() => {
|
||||
should_cancel(job_cancellation, cancellation_token, wait_cancel).await;
|
||||
}
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
should_cancel(job_cancellation, cancellation_token,wait_cancel).await;
|
||||
}
|
||||
_ = signal_unix_terminate() => {
|
||||
should_cancel(job_cancellation, cancellation_token, wait_cancel).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut futures = FuturesUnordered::new();
|
||||
for channel in channels.iter_mut() {
|
||||
futures.push(channel.recv());
|
||||
}
|
||||
|
||||
let mut errors = Vec::new();
|
||||
while let Some(Some(msg)) = futures.next().await {
|
||||
match msg.res {
|
||||
Err(e) => {
|
||||
@@ -177,21 +208,20 @@ impl Mad {
|
||||
component = msg.name,
|
||||
"component ran to completion with error"
|
||||
);
|
||||
errors.push(e);
|
||||
}
|
||||
Ok(_) => {
|
||||
tracing::debug!(component = msg.name, "component ran to completion");
|
||||
}
|
||||
}
|
||||
|
||||
job_cancellation.cancel();
|
||||
if let Some(cancel_wait) = self.should_cancel {
|
||||
tokio::time::sleep(cancel_wait).await;
|
||||
|
||||
cancellation_token.cancel();
|
||||
}
|
||||
job_done.cancel();
|
||||
}
|
||||
|
||||
tracing::debug!("ran components");
|
||||
if !errors.is_empty() {
|
||||
return Err(MadError::AggregateError(AggregateError { errors }));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@@ -1,6 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use notmad::{Component, Mad};
|
||||
use rand::Rng;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing_test::traced_test;
|
||||
|
||||
@@ -86,3 +89,51 @@ async fn test_can_run_components() -> anyhow::Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[traced_test]
|
||||
async fn test_can_shutdown_gracefully() -> anyhow::Result<()> {
|
||||
let check = Arc::new(Mutex::new(None));
|
||||
|
||||
Mad::builder()
|
||||
.add_fn({
|
||||
let check = check.clone();
|
||||
|
||||
move |cancel| {
|
||||
let check = check.clone();
|
||||
|
||||
async move {
|
||||
let start = std::time::SystemTime::now();
|
||||
tracing::info!("waiting for cancel");
|
||||
cancel.cancelled().await;
|
||||
tracing::info!("submitting check");
|
||||
let mut check = check.lock().await;
|
||||
let elapsed = start.elapsed().expect("to be able to get elapsed");
|
||||
*check = Some(elapsed);
|
||||
tracing::info!("check submitted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})
|
||||
.add_fn(|_| async move {
|
||||
tracing::info!("starting sleep");
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
tracing::info!("sleep ended");
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.run()
|
||||
.await?;
|
||||
|
||||
let check = check
|
||||
.lock()
|
||||
.await
|
||||
.expect("to be able to get a duration from cancel");
|
||||
|
||||
// We default wait 100 ms for graceful shutdown, and we explicitly wait 100ms in the sleep routine
|
||||
tracing::info!("check millis: {}", check.as_millis());
|
||||
assert!(check.as_millis() < 250);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
Reference in New Issue
Block a user