15 Commits

Author SHA1 Message Date
72755f9cf1 chore(release): v0.7.1 (#12)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.7.1

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: https://git.front.kjuulh.io/kjuulh/mad/pulls/12
2024-11-24 11:28:02 +01:00
ae0b8b703e fix: make sure to close on final
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-24 11:24:13 +01:00
3c3f638004 chore(release): v0.7.0 (#11)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.7.0

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: https://git.front.kjuulh.io/kjuulh/mad/pulls/11
2024-11-24 10:49:56 +01:00
ea5287152c feat: actually bubble up errors
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-24 10:47:56 +01:00
14371cdfd7 fix(deps): update rust crate thiserror to v2 (#9)
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-24 02:52:50 +01:00
3a1b1673ef chore(release): v0.6.0 (#8)
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
chore(release): 0.6.0

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: https://git.front.kjuulh.io/kjuulh/mad/pulls/8
2024-11-24 00:26:50 +01:00
89cbae24d0 chore: Configure Renovate (#7)
All checks were successful
continuous-integration/drone/push Build is passing
Add renovate.json

Reviewed-on: https://git.front.kjuulh.io/kjuulh/mad/pulls/7
2024-11-24 00:26:37 +01:00
7c1b317d08 feat: adding test to make sure we can gracefully shutdown
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-24 00:25:02 +01:00
1fec4e3708 feat: make sure to close down properly
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-24 00:08:03 +01:00
0eb24aa937 chore(release): v0.5.0 (#6)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.5.0

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: https://git.front.kjuulh.io/kjuulh/mad/pulls/6
2024-11-19 17:21:46 +01:00
5c88cdd3e3 feat: update name
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-19 17:20:41 +01:00
d51716893f feat: respect sigterm
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-19 16:41:12 +01:00
ff350f9193 feat: include author
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-09 00:28:49 +01:00
3d774f6d9c feat: update with rename
Some checks failed
continuous-integration/drone/push Build is failing
Signed-off-by: kjuulh <contact@kjuulh.io>
2024-11-09 00:28:33 +01:00
b78423377c docs: add examples
All checks were successful
continuous-integration/drone/push Build is passing
this is to show how we can use closures in the mad component context. It isn't super pretty because of the async closure, so we need to show the slighly complicated syntax

Signed-off-by: kjuulh <contact@kjuulh.io>
2024-08-07 17:09:52 +02:00
12 changed files with 281 additions and 132 deletions

View File

@@ -6,6 +6,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [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
- update name
- respect sigterm
- include author
- update with rename
### Docs
- add examples
## [0.4.0] - 2024-08-07 ## [0.4.0] - 2024-08-07
### Added ### Added

194
Cargo.lock generated
View File

@@ -1,21 +1,21 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.22.0" version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
[[package]] [[package]]
name = "adler" name = "adler2"
version = "1.0.2" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@@ -28,15 +28,15 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.86" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.81" version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -45,23 +45,23 @@ dependencies = [
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.73" version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"windows-targets",
] ]
[[package]] [[package]]
@@ -78,15 +78,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.7.1" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
[[package]]
name = "cc"
version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@@ -96,9 +90,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -111,9 +105,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@@ -121,15 +115,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@@ -138,15 +132,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -155,21 +149,21 @@ dependencies = [
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.30" version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -196,9 +190,9 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.29.0" version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
@@ -214,9 +208,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.155" version = "0.2.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@@ -234,23 +228,6 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "mad"
version = "0.3.0"
dependencies = [
"anyhow",
"async-trait",
"futures",
"futures-util",
"rand",
"thiserror",
"tokio",
"tokio-util",
"tracing",
"tracing-subscriber",
"tracing-test",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@@ -268,18 +245,18 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.4" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
dependencies = [ dependencies = [
"adler", "adler2",
] ]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
@@ -287,6 +264,23 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "notmad"
version = "0.7.0"
dependencies = [
"anyhow",
"async-trait",
"futures",
"futures-util",
"rand",
"thiserror",
"tokio",
"tokio-util",
"tracing",
"tracing-subscriber",
"tracing-test",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"
@@ -299,18 +293,18 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.36.3" version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.19.0" version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "overload" name = "overload"
@@ -343,9 +337,9 @@ dependencies = [
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.14" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@@ -364,18 +358,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.36" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -412,23 +406,23 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.3" version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.6" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.4.7", "regex-automata 0.4.9",
"regex-syntax 0.8.4", "regex-syntax 0.8.5",
] ]
[[package]] [[package]]
@@ -442,13 +436,13 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.7" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.8.4", "regex-syntax 0.8.5",
] ]
[[package]] [[package]]
@@ -459,9 +453,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
@@ -520,9 +514,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.72" version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -531,18 +525,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.63" version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.63" version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -561,9 +555,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.39.2" version = "1.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@@ -590,9 +584,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.11" version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@@ -686,9 +680,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]] [[package]]
name = "valuable" name = "valuable"

View File

@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.4.0" version = "0.7.1"
[workspace.dependencies] [workspace.dependencies]
mad = { path = "crates/mad" } mad = { path = "crates/mad" }

View File

@@ -41,3 +41,11 @@ async fn main() -> anyhow::Result<()> {
} }
``` ```
## Examples
Can be found (here)[crates/mad/examples]
- basic
- fn
- signals
- error_log

View File

@@ -1,6 +1,10 @@
[package] [package]
name = "mad" name = "notmad"
version.workspace = true version.workspace = true
description = "notmad is a life-cycle manager for long running rust operations"
license = "MIT"
repository = "https://github.com/kjuulh/mad"
author = "kjuulh"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@@ -9,7 +13,7 @@ async-trait = "0.1.81"
futures = "0.3.30" futures = "0.3.30"
futures-util = "0.3.30" futures-util = "0.3.30"
rand = "0.8.5" rand = "0.8.5"
thiserror = "1.0.63" thiserror = "2.0.0"
tokio.workspace = true tokio.workspace = true
tokio-util = "0.7.11" tokio-util = "0.7.11"
tracing.workspace = true tracing.workspace = true

View File

@@ -5,12 +5,12 @@ use tracing::Level;
struct WaitServer {} struct WaitServer {}
#[async_trait] #[async_trait]
impl mad::Component for WaitServer { impl notmad::Component for WaitServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("WaitServer".into()) Some("WaitServer".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
let millis_wait = rand::thread_rng().gen_range(500..3000); let millis_wait = rand::thread_rng().gen_range(500..3000);
tracing::debug!("waiting: {}ms", millis_wait); tracing::debug!("waiting: {}ms", millis_wait);
@@ -28,7 +28,7 @@ async fn main() -> anyhow::Result<()> {
.with_max_level(Level::TRACE) .with_max_level(Level::TRACE)
.init(); .init();
mad::Mad::builder() notmad::Mad::builder()
.add(WaitServer {}) .add(WaitServer {})
.add(WaitServer {}) .add(WaitServer {})
.add(WaitServer {}) .add(WaitServer {})

View File

@@ -5,12 +5,12 @@ use tracing::Level;
struct ErrorServer {} struct ErrorServer {}
#[async_trait] #[async_trait]
impl mad::Component for ErrorServer { impl notmad::Component for ErrorServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("ErrorServer".into()) Some("ErrorServer".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
let millis_wait = rand::thread_rng().gen_range(500..3000); let millis_wait = rand::thread_rng().gen_range(500..3000);
tracing::debug!("waiting: {}ms", millis_wait); tracing::debug!("waiting: {}ms", millis_wait);
@@ -18,7 +18,7 @@ impl mad::Component for ErrorServer {
// Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely // Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely
tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await; tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await;
Err(mad::MadError::Inner(anyhow::anyhow!("expected error"))) Err(notmad::MadError::Inner(anyhow::anyhow!("expected error")))
} }
} }
@@ -30,7 +30,7 @@ async fn main() -> anyhow::Result<()> {
// Do note that only the first server which returns an error is guaranteed to be handled. This is because if servers don't respect cancellation, they will be dropped // Do note that only the first server which returns an error is guaranteed to be handled. This is because if servers don't respect cancellation, they will be dropped
mad::Mad::builder() notmad::Mad::builder()
.add(ErrorServer {}) .add(ErrorServer {})
.add(ErrorServer {}) .add(ErrorServer {})
.add(ErrorServer {}) .add(ErrorServer {})

View File

@@ -5,12 +5,12 @@ use tracing::Level;
struct WaitServer {} struct WaitServer {}
#[async_trait] #[async_trait]
impl mad::Component for WaitServer { impl notmad::Component for WaitServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("WaitServer".into()) Some("WaitServer".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, _cancellation: CancellationToken) -> Result<(), notmad::MadError> {
let millis_wait = rand::thread_rng().gen_range(500..3000); let millis_wait = rand::thread_rng().gen_range(500..3000);
tracing::debug!("waiting: {}ms", millis_wait); tracing::debug!("waiting: {}ms", millis_wait);
@@ -28,9 +28,11 @@ async fn main() -> anyhow::Result<()> {
.with_max_level(Level::TRACE) .with_max_level(Level::TRACE)
.init(); .init();
mad::Mad::builder() let item = "some item".to_string();
notmad::Mad::builder()
.add(WaitServer {}) .add(WaitServer {})
.add_fn(|cancel| async move { .add_fn(|_cancel| async move {
let millis_wait = 50; let millis_wait = 50;
tracing::debug!("waiting: {}ms", millis_wait); tracing::debug!("waiting: {}ms", millis_wait);
@@ -40,6 +42,24 @@ async fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
}) })
.add_fn(move |_cancel| {
// I am an actual closure
let item = item.clone();
async move {
let _item = item;
let millis_wait = 50;
tracing::debug!("waiting: {}ms", millis_wait);
// Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely
tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await;
Ok(())
}
})
.run() .run()
.await?; .await?;

View File

@@ -5,12 +5,12 @@ use tracing::Level;
struct WaitServer {} struct WaitServer {}
#[async_trait] #[async_trait]
impl mad::Component for WaitServer { impl notmad::Component for WaitServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("WaitServer".into()) Some("WaitServer".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
let millis_wait = rand::thread_rng().gen_range(500..3000); let millis_wait = rand::thread_rng().gen_range(500..3000);
tracing::debug!("waiting: {}ms", millis_wait); tracing::debug!("waiting: {}ms", millis_wait);
@@ -24,12 +24,12 @@ impl mad::Component for WaitServer {
struct RespectCancel {} struct RespectCancel {}
#[async_trait] #[async_trait]
impl mad::Component for RespectCancel { impl notmad::Component for RespectCancel {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("RespectCancel".into()) Some("RespectCancel".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
cancellation.cancelled().await; cancellation.cancelled().await;
tracing::debug!("stopping because job is cancelled"); tracing::debug!("stopping because job is cancelled");
@@ -39,12 +39,12 @@ impl mad::Component for RespectCancel {
struct NeverStopServer {} struct NeverStopServer {}
#[async_trait] #[async_trait]
impl mad::Component for NeverStopServer { impl notmad::Component for NeverStopServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("NeverStopServer".into()) Some("NeverStopServer".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
// Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely // Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely
tokio::time::sleep(std::time::Duration::from_millis(999999999)).await; tokio::time::sleep(std::time::Duration::from_millis(999999999)).await;
@@ -58,7 +58,7 @@ async fn main() -> anyhow::Result<()> {
.with_max_level(Level::TRACE) .with_max_level(Level::TRACE)
.init(); .init();
mad::Mad::builder() notmad::Mad::builder()
.add(WaitServer {}) .add(WaitServer {})
.add(NeverStopServer {}) .add(NeverStopServer {})
.add(RespectCancel {}) .add(RespectCancel {})

View File

@@ -1,6 +1,7 @@
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
use futures_util::StreamExt; use futures_util::StreamExt;
use std::{fmt::Display, sync::Arc}; use std::{fmt::Display, sync::Arc};
use tokio::signal::unix::{signal, SignalKind};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
@@ -132,6 +133,7 @@ impl Mad {
let mut channels = Vec::new(); let mut channels = Vec::new();
let cancellation_token = CancellationToken::new(); let cancellation_token = CancellationToken::new();
let job_cancellation = CancellationToken::new(); let job_cancellation = CancellationToken::new();
let job_done = CancellationToken::new();
for comp in &self.components { for comp in &self.components {
let comp = comp.clone(); let comp = comp.clone();
@@ -153,18 +155,51 @@ impl Mad {
res = comp.run(job_cancellation) => { res = comp.run(job_cancellation) => {
error_tx.send(CompletionResult { res , name }).await error_tx.send(CompletionResult { res , name }).await
} }
_ = tokio::signal::ctrl_c() => {
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(); let mut futures = FuturesUnordered::new();
for channel in channels.iter_mut() { for channel in channels.iter_mut() {
futures.push(channel.recv()); futures.push(channel.recv());
} }
let mut errors = Vec::new();
while let Some(Some(msg)) = futures.next().await { while let Some(Some(msg)) = futures.next().await {
match msg.res { match msg.res {
Err(e) => { Err(e) => {
@@ -173,21 +208,20 @@ impl Mad {
component = msg.name, component = msg.name,
"component ran to completion with error" "component ran to completion with error"
); );
errors.push(e);
} }
Ok(_) => { Ok(_) => {
tracing::debug!(component = msg.name, "component ran to completion"); tracing::debug!(component = msg.name, "component ran to completion");
} }
} }
job_cancellation.cancel(); job_done.cancel();
if let Some(cancel_wait) = self.should_cancel {
tokio::time::sleep(cancel_wait).await;
cancellation_token.cancel();
}
} }
tracing::debug!("ran components"); tracing::debug!("ran components");
if !errors.is_empty() {
return Err(MadError::AggregateError(AggregateError { errors }));
}
Ok(()) Ok(())
} }
@@ -209,6 +243,11 @@ impl Mad {
} }
} }
async fn signal_unix_terminate() {
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to bind SIGTERM handler");
sigterm.recv().await;
}
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait Component { pub trait Component {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {

View File

@@ -1,6 +1,9 @@
use std::sync::Arc;
use async_trait::async_trait; use async_trait::async_trait;
use mad::{Component, Mad}; use notmad::{Component, Mad};
use rand::Rng; use rand::Rng;
use tokio::sync::Mutex;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing_test::traced_test; use tracing_test::traced_test;
@@ -12,7 +15,7 @@ impl Component for NeverEndingRun {
Some("NeverEndingRun".into()) Some("NeverEndingRun".into())
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), notmad::MadError> {
let millis_wait = rand::thread_rng().gen_range(50..1000); let millis_wait = rand::thread_rng().gen_range(50..1000);
tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await; tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await;
@@ -86,3 +89,51 @@ async fn test_can_run_components() -> anyhow::Result<()> {
Ok(()) 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
View File

@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}