agy-superpowers 5.1.4 → 5.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/package.json +1 -1
  2. package/template/agent/rules/debug-confirmation-policy.md +34 -0
  3. package/template/agent/rules/language-matching.md +32 -0
  4. package/template/agent/skills/rust-developer/SKILL.md +281 -0
  5. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +231 -0
  6. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +124 -0
  7. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +131 -0
  8. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +132 -0
  9. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +95 -0
  10. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +141 -0
  11. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +125 -0
  12. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +127 -0
  13. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +120 -0
  14. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +131 -0
  15. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +156 -0
  16. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +122 -0
  17. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +167 -0
  18. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +134 -0
  19. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +143 -0
  20. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +121 -0
  21. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +143 -0
  22. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +187 -0
  23. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +165 -0
  24. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +177 -0
  25. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +163 -0
  26. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +146 -0
  27. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +142 -0
  28. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +160 -0
  29. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +125 -0
  30. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +162 -0
  31. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +177 -0
  32. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +184 -0
  33. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +168 -0
  34. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +182 -0
  35. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +199 -0
  36. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +175 -0
  37. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +185 -0
  38. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +203 -0
  39. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +171 -0
  40. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +158 -0
  41. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +195 -0
  42. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +171 -0
  43. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +156 -0
  44. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +191 -0
  45. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +198 -0
  46. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +154 -0
  47. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +167 -0
  48. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +169 -0
  49. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +172 -0
  50. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +189 -0
  51. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +113 -0
  52. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +147 -0
  53. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +122 -0
  54. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +161 -0
  55. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +149 -0
  56. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +138 -0
  57. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +169 -0
  58. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +116 -0
  59. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +128 -0
  60. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +136 -0
  61. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +131 -0
  62. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +179 -0
  63. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +144 -0
  64. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +152 -0
  65. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +145 -0
  66. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +133 -0
  67. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +152 -0
  68. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +124 -0
  69. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +115 -0
  70. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +151 -0
  71. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +130 -0
  72. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +155 -0
  73. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +171 -0
  74. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +138 -0
  75. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +107 -0
  76. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +154 -0
  77. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +118 -0
  78. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +157 -0
  79. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +133 -0
  80. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +131 -0
  81. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +136 -0
  82. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +135 -0
  83. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +122 -0
  84. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +172 -0
  85. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +168 -0
  86. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +142 -0
  87. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +168 -0
  88. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +147 -0
  89. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +158 -0
  90. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +139 -0
  91. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +147 -0
  92. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +149 -0
  93. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +174 -0
  94. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +159 -0
  95. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +138 -0
  96. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +142 -0
  97. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +156 -0
  98. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +172 -0
  99. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +164 -0
  100. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +99 -0
  101. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +104 -0
  102. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +94 -0
  103. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +78 -0
  104. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +76 -0
  105. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +123 -0
  106. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +127 -0
  107. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +129 -0
  108. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +131 -0
  109. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +142 -0
  110. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +86 -0
  111. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +154 -0
  112. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +118 -0
  113. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +92 -0
  114. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +65 -0
  115. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +101 -0
  116. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +161 -0
  117. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +187 -0
  118. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +142 -0
  119. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +152 -0
  120. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +141 -0
  121. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +181 -0
  122. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +160 -0
  123. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +171 -0
  124. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +130 -0
  125. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +167 -0
  126. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +144 -0
  127. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +154 -0
  128. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +141 -0
  129. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +95 -0
  130. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +135 -0
  131. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +124 -0
  132. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +135 -0
  133. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +134 -0
  134. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +134 -0
  135. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +105 -0
  136. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +65 -0
  137. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +97 -0
  138. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +122 -0
  139. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +119 -0
  140. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +153 -0
  141. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +136 -0
  142. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +133 -0
  143. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +120 -0
  144. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +137 -0
  145. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +134 -0
  146. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +150 -0
  147. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +123 -0
  148. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +113 -0
  149. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +175 -0
  150. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +149 -0
  151. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +142 -0
  152. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +133 -0
  153. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +148 -0
  154. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +130 -0
  155. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +120 -0
  156. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +155 -0
  157. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +139 -0
  158. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +135 -0
  159. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +162 -0
  160. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +186 -0
  161. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +162 -0
  162. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +160 -0
  163. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +151 -0
  164. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +171 -0
  165. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +142 -0
  166. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +168 -0
  167. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +151 -0
  168. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +144 -0
  169. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +189 -0
  170. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +226 -0
  171. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +161 -0
  172. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +130 -0
  173. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +154 -0
  174. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +127 -0
  175. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +154 -0
  176. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +142 -0
  177. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +146 -0
  178. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +160 -0
  179. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +159 -0
  180. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +144 -0
  181. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +137 -0
  182. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +188 -0
  183. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +143 -0
  184. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +131 -0
  185. package/template/agent/skills/systematic-debugging/SKILL.md +17 -0
@@ -0,0 +1,175 @@
1
+ # async-bounded-channel
2
+
3
+ > Use bounded channels to apply backpressure and prevent unbounded memory growth
4
+
5
+ ## Why It Matters
6
+
7
+ Unbounded channels grow without limit when producers outpace consumers. In production, this leads to memory exhaustion. Bounded channels apply backpressure—producers wait when the channel is full, naturally throttling the system. This prevents OOM and makes resource usage predictable.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ use tokio::sync::mpsc;
13
+
14
+ // Unbounded channel - can grow forever
15
+ let (tx, mut rx) = mpsc::unbounded_channel::<Message>();
16
+
17
+ // Fast producer, slow consumer = unbounded memory growth
18
+ tokio::spawn(async move {
19
+ loop {
20
+ let msg = generate_message();
21
+ tx.send(msg).unwrap(); // Never blocks, never fails (until OOM)
22
+ }
23
+ });
24
+
25
+ tokio::spawn(async move {
26
+ while let Some(msg) = rx.recv().await {
27
+ slow_process(msg).await; // Can't keep up
28
+ }
29
+ });
30
+ // Memory grows unboundedly until crash
31
+ ```
32
+
33
+ ## Good
34
+
35
+ ```rust
36
+ use tokio::sync::mpsc;
37
+
38
+ // Bounded channel - backpressure when full
39
+ let (tx, mut rx) = mpsc::channel::<Message>(100); // Max 100 items
40
+
41
+ // Producer waits when channel full
42
+ tokio::spawn(async move {
43
+ loop {
44
+ let msg = generate_message();
45
+ // Blocks if channel is full - natural backpressure
46
+ tx.send(msg).await.unwrap();
47
+ }
48
+ });
49
+
50
+ tokio::spawn(async move {
51
+ while let Some(msg) = rx.recv().await {
52
+ slow_process(msg).await;
53
+ }
54
+ });
55
+ // Memory usage capped at ~100 messages
56
+ ```
57
+
58
+ ## Choosing Buffer Size
59
+
60
+ ```rust
61
+ // Too small: frequent blocking, reduced throughput
62
+ let (tx, rx) = mpsc::channel::<Item>(1);
63
+
64
+ // Too large: delayed backpressure, memory waste
65
+ let (tx, rx) = mpsc::channel::<Item>(1_000_000);
66
+
67
+ // Guidelines:
68
+ // - Start with expected burst size
69
+ // - Measure actual usage in production
70
+ // - Err on the smaller side initially
71
+
72
+ // Small items, high throughput
73
+ let (tx, rx) = mpsc::channel::<u64>(1000);
74
+
75
+ // Large items, moderate throughput
76
+ let (tx, rx) = mpsc::channel::<LargeStruct>(100);
77
+
78
+ // Low latency requirement
79
+ let (tx, rx) = mpsc::channel::<Command>(10);
80
+ ```
81
+
82
+ ## Handling Full Channel
83
+
84
+ ```rust
85
+ use tokio::sync::mpsc;
86
+ use tokio::time::{timeout, Duration};
87
+
88
+ let (tx, mut rx) = mpsc::channel::<Message>(100);
89
+
90
+ // Option 1: Wait indefinitely (default)
91
+ tx.send(msg).await?;
92
+
93
+ // Option 2: Try send, fail if full
94
+ match tx.try_send(msg) {
95
+ Ok(()) => println!("Sent"),
96
+ Err(TrySendError::Full(msg)) => {
97
+ println!("Channel full, dropping message");
98
+ }
99
+ Err(TrySendError::Closed(msg)) => {
100
+ println!("Receiver dropped");
101
+ }
102
+ }
103
+
104
+ // Option 3: Timeout
105
+ match timeout(Duration::from_secs(1), tx.send(msg)).await {
106
+ Ok(Ok(())) => println!("Sent"),
107
+ Ok(Err(_)) => println!("Channel closed"),
108
+ Err(_) => println!("Timeout - channel full for too long"),
109
+ }
110
+
111
+ // Option 4: send with permit reservation
112
+ let permit = tx.reserve().await?;
113
+ permit.send(msg); // Guaranteed to succeed
114
+ ```
115
+
116
+ ## Channel Types
117
+
118
+ ```rust
119
+ // mpsc: many producers, single consumer
120
+ let (tx, rx) = mpsc::channel::<Message>(100);
121
+ let tx2 = tx.clone(); // Can clone sender
122
+
123
+ // oneshot: single value, one producer, one consumer
124
+ let (tx, rx) = oneshot::channel::<Response>();
125
+ tx.send(response); // Can only send once
126
+
127
+ // broadcast: multiple consumers, each gets all messages
128
+ let (tx, _) = broadcast::channel::<Event>(100);
129
+ let mut rx1 = tx.subscribe();
130
+ let mut rx2 = tx.subscribe();
131
+
132
+ // watch: single latest value, multiple consumers
133
+ let (tx, rx) = watch::channel::<State>(initial);
134
+ // Receivers see latest value, not all values
135
+ ```
136
+
137
+ ## Worker Pool Pattern
138
+
139
+ ```rust
140
+ async fn process_with_workers(items: Vec<Item>) -> Vec<Result> {
141
+ let (tx, rx) = mpsc::channel(100);
142
+ let rx = Arc::new(Mutex::new(rx));
143
+
144
+ // Spawn worker pool
145
+ let workers: Vec<_> = (0..4).map(|_| {
146
+ let rx = rx.clone();
147
+ tokio::spawn(async move {
148
+ loop {
149
+ let item = {
150
+ let mut rx = rx.lock().await;
151
+ rx.recv().await
152
+ };
153
+ match item {
154
+ Some(item) => process(item).await,
155
+ None => break,
156
+ }
157
+ }
158
+ })
159
+ }).collect();
160
+
161
+ // Send items
162
+ for item in items {
163
+ tx.send(item).await.unwrap();
164
+ }
165
+ drop(tx); // Signal workers to stop
166
+
167
+ futures::future::join_all(workers).await;
168
+ }
169
+ ```
170
+
171
+ ## See Also
172
+
173
+ - [async-mpsc-queue](./async-mpsc-queue.md) - Multi-producer patterns
174
+ - [async-oneshot-response](./async-oneshot-response.md) - Request-response pattern
175
+ - [async-watch-latest](./async-watch-latest.md) - Latest-value broadcasting
@@ -0,0 +1,185 @@
1
+ # async-broadcast-pubsub
2
+
3
+ > Use `broadcast` channel for pub/sub where all subscribers receive all messages
4
+
5
+ ## Why It Matters
6
+
7
+ Unlike `mpsc` where one consumer receives each message, `broadcast` delivers each message to all subscribers. This is ideal for event broadcasting, real-time notifications, or when multiple components need to react to the same events independently.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ use tokio::sync::mpsc;
13
+
14
+ // mpsc only delivers to ONE consumer
15
+ let (tx, mut rx) = mpsc::channel::<Event>(100);
16
+
17
+ // Only one of these receives each message!
18
+ let mut rx2 = ???; // Can't clone receiver
19
+ ```
20
+
21
+ ## Good
22
+
23
+ ```rust
24
+ use tokio::sync::broadcast;
25
+
26
+ // broadcast delivers to ALL subscribers
27
+ let (tx, _) = broadcast::channel::<Event>(100);
28
+
29
+ // Each subscriber gets ALL messages
30
+ let mut rx1 = tx.subscribe();
31
+ let mut rx2 = tx.subscribe();
32
+
33
+ tokio::spawn(async move {
34
+ while let Ok(event) = rx1.recv().await {
35
+ handle_in_logger(event);
36
+ }
37
+ });
38
+
39
+ tokio::spawn(async move {
40
+ while let Ok(event) = rx2.recv().await {
41
+ handle_in_metrics(event);
42
+ }
43
+ });
44
+
45
+ // Both subscribers receive this
46
+ tx.send(Event::UserLogin { user_id: 42 })?;
47
+ ```
48
+
49
+ ## Broadcast Semantics
50
+
51
+ ```rust
52
+ use tokio::sync::broadcast;
53
+
54
+ let (tx, mut rx1) = broadcast::channel::<i32>(16);
55
+ let mut rx2 = tx.subscribe();
56
+
57
+ tx.send(1)?;
58
+ tx.send(2)?;
59
+
60
+ // Both receive all messages
61
+ assert_eq!(rx1.recv().await?, 1);
62
+ assert_eq!(rx1.recv().await?, 2);
63
+ assert_eq!(rx2.recv().await?, 1);
64
+ assert_eq!(rx2.recv().await?, 2);
65
+ ```
66
+
67
+ ## Handling Lagging Receivers
68
+
69
+ ```rust
70
+ use tokio::sync::broadcast::{self, error::RecvError};
71
+
72
+ let (tx, mut rx) = broadcast::channel::<Event>(16);
73
+
74
+ loop {
75
+ match rx.recv().await {
76
+ Ok(event) => {
77
+ process(event);
78
+ }
79
+ Err(RecvError::Lagged(count)) => {
80
+ // Receiver couldn't keep up, missed `count` messages
81
+ log::warn!("Missed {} events", count);
82
+ // Continue receiving new messages
83
+ }
84
+ Err(RecvError::Closed) => {
85
+ break; // All senders dropped
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## Event Bus Pattern
92
+
93
+ ```rust
94
+ use tokio::sync::broadcast;
95
+
96
+ #[derive(Clone, Debug)]
97
+ enum AppEvent {
98
+ UserLoggedIn { user_id: u64 },
99
+ OrderCreated { order_id: u64 },
100
+ SystemShutdown,
101
+ }
102
+
103
+ struct EventBus {
104
+ tx: broadcast::Sender<AppEvent>,
105
+ }
106
+
107
+ impl EventBus {
108
+ fn new() -> Self {
109
+ let (tx, _) = broadcast::channel(1000);
110
+ EventBus { tx }
111
+ }
112
+
113
+ fn publish(&self, event: AppEvent) {
114
+ // Ignore error if no subscribers
115
+ let _ = self.tx.send(event);
116
+ }
117
+
118
+ fn subscribe(&self) -> broadcast::Receiver<AppEvent> {
119
+ self.tx.subscribe()
120
+ }
121
+ }
122
+
123
+ // Usage
124
+ let bus = EventBus::new();
125
+
126
+ // Logger subscribes
127
+ let mut log_rx = bus.subscribe();
128
+ tokio::spawn(async move {
129
+ while let Ok(event) = log_rx.recv().await {
130
+ log::info!("Event: {:?}", event);
131
+ }
132
+ });
133
+
134
+ // Metrics subscribes
135
+ let mut metrics_rx = bus.subscribe();
136
+ tokio::spawn(async move {
137
+ while let Ok(event) = metrics_rx.recv().await {
138
+ record_metric(&event);
139
+ }
140
+ });
141
+
142
+ // Publish events
143
+ bus.publish(AppEvent::UserLoggedIn { user_id: 42 });
144
+ ```
145
+
146
+ ## Broadcast vs Watch
147
+
148
+ ```rust
149
+ // broadcast: subscribers get ALL messages
150
+ // Good for: events, logs, notifications
151
+ let (tx, _) = broadcast::channel::<Event>(100);
152
+
153
+ // watch: subscribers get LATEST value only
154
+ // Good for: config changes, state updates
155
+ let (tx, _) = watch::channel(initial_state);
156
+
157
+ // If subscriber is slow:
158
+ // - broadcast: they receive old messages (or lag)
159
+ // - watch: they skip to latest (no history)
160
+ ```
161
+
162
+ ## Clone Requirement
163
+
164
+ ```rust
165
+ // broadcast requires Clone because message is cloned to each receiver
166
+ use tokio::sync::broadcast;
167
+
168
+ #[derive(Clone)] // Required for broadcast
169
+ struct Event {
170
+ data: String,
171
+ }
172
+
173
+ let (tx, _) = broadcast::channel::<Event>(100);
174
+
175
+ // For non-Clone types, wrap in Arc
176
+ use std::sync::Arc;
177
+
178
+ let (tx, _) = broadcast::channel::<Arc<LargeNonClone>>(100);
179
+ ```
180
+
181
+ ## See Also
182
+
183
+ - [async-mpsc-queue](./async-mpsc-queue.md) - Single-consumer channels
184
+ - [async-watch-latest](./async-watch-latest.md) - Latest-value only
185
+ - [async-bounded-channel](./async-bounded-channel.md) - Buffer sizing
@@ -0,0 +1,203 @@
1
+ # async-cancellation-token
2
+
3
+ > Use `CancellationToken` for graceful shutdown and task cancellation
4
+
5
+ ## Why It Matters
6
+
7
+ Dropping a `JoinHandle` doesn't cancel the task—it just detaches it. For graceful shutdown, you need explicit cancellation. `tokio_util::sync::CancellationToken` provides a cooperative cancellation mechanism that tasks can check and respond to, enabling clean resource cleanup.
8
+
9
+ ## Bad
10
+
11
+ ```rust
12
+ // Dropping handle doesn't stop the task
13
+ let handle = tokio::spawn(async {
14
+ loop {
15
+ do_work().await;
16
+ }
17
+ });
18
+
19
+ drop(handle); // Task continues running in background!
20
+
21
+ // Using bool flag - not async-aware
22
+ let running = Arc::new(AtomicBool::new(true));
23
+
24
+ tokio::spawn({
25
+ let running = running.clone();
26
+ async move {
27
+ while running.load(Ordering::Relaxed) {
28
+ do_work().await; // Can't wake up if blocked here
29
+ }
30
+ }
31
+ });
32
+
33
+ running.store(false, Ordering::Relaxed);
34
+ // Task won't stop until current do_work() completes
35
+ ```
36
+
37
+ ## Good
38
+
39
+ ```rust
40
+ use tokio_util::sync::CancellationToken;
41
+
42
+ let token = CancellationToken::new();
43
+
44
+ let handle = tokio::spawn({
45
+ let token = token.clone();
46
+ async move {
47
+ loop {
48
+ tokio::select! {
49
+ _ = token.cancelled() => {
50
+ println!("Shutting down gracefully");
51
+ cleanup().await;
52
+ break;
53
+ }
54
+ _ = do_work() => {
55
+ // Work completed
56
+ }
57
+ }
58
+ }
59
+ }
60
+ });
61
+
62
+ // Later: trigger cancellation
63
+ token.cancel();
64
+ handle.await?; // Task completes cleanly
65
+ ```
66
+
67
+ ## CancellationToken API
68
+
69
+ ```rust
70
+ use tokio_util::sync::CancellationToken;
71
+
72
+ // Create token
73
+ let token = CancellationToken::new();
74
+
75
+ // Clone for sharing (cheap Arc-based clone)
76
+ let token2 = token.clone();
77
+
78
+ // Check if cancelled (non-blocking)
79
+ if token.is_cancelled() {
80
+ return;
81
+ }
82
+
83
+ // Wait for cancellation (async)
84
+ token.cancelled().await;
85
+
86
+ // Trigger cancellation
87
+ token.cancel();
88
+
89
+ // Child tokens - cancelled when parent is cancelled
90
+ let child = token.child_token();
91
+ ```
92
+
93
+ ## Hierarchical Cancellation
94
+
95
+ ```rust
96
+ async fn run_server(shutdown: CancellationToken) {
97
+ let listener = TcpListener::bind("0.0.0.0:8080").await?;
98
+
99
+ loop {
100
+ tokio::select! {
101
+ _ = shutdown.cancelled() => {
102
+ println!("Server shutting down");
103
+ break;
104
+ }
105
+ result = listener.accept() => {
106
+ let (socket, _) = result?;
107
+ // Each connection gets child token
108
+ let conn_token = shutdown.child_token();
109
+ tokio::spawn(handle_connection(socket, conn_token));
110
+ }
111
+ }
112
+ }
113
+
114
+ // Child tokens auto-cancelled when we exit
115
+ }
116
+
117
+ async fn handle_connection(socket: TcpStream, token: CancellationToken) {
118
+ loop {
119
+ tokio::select! {
120
+ _ = token.cancelled() => {
121
+ // Connection cleanup
122
+ break;
123
+ }
124
+ data = socket.read() => {
125
+ // Handle data
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ ## Graceful Shutdown Pattern
133
+
134
+ ```rust
135
+ use tokio::signal;
136
+
137
+ async fn main() -> Result<()> {
138
+ let shutdown = CancellationToken::new();
139
+
140
+ // Spawn signal handler
141
+ let shutdown_trigger = shutdown.clone();
142
+ tokio::spawn(async move {
143
+ signal::ctrl_c().await.expect("failed to listen for Ctrl+C");
144
+ println!("Received Ctrl+C, initiating shutdown...");
145
+ shutdown_trigger.cancel();
146
+ });
147
+
148
+ // Run application with shutdown token
149
+ run_app(shutdown).await
150
+ }
151
+
152
+ async fn run_app(shutdown: CancellationToken) -> Result<()> {
153
+ let mut tasks = JoinSet::new();
154
+
155
+ tasks.spawn(worker_task(shutdown.child_token()));
156
+ tasks.spawn(server_task(shutdown.child_token()));
157
+
158
+ // Wait for shutdown or task completion
159
+ tokio::select! {
160
+ _ = shutdown.cancelled() => {
161
+ println!("Shutdown requested, waiting for tasks...");
162
+ }
163
+ Some(result) = tasks.join_next() => {
164
+ // A task completed/failed
165
+ result??;
166
+ }
167
+ }
168
+
169
+ // Wait for remaining tasks with timeout
170
+ tokio::time::timeout(
171
+ Duration::from_secs(30),
172
+ async { while tasks.join_next().await.is_some() {} }
173
+ ).await.ok();
174
+
175
+ Ok(())
176
+ }
177
+ ```
178
+
179
+ ## DropGuard Pattern
180
+
181
+ ```rust
182
+ use tokio_util::sync::CancellationToken;
183
+
184
+ // Auto-cancel on drop
185
+ let token = CancellationToken::new();
186
+ let guard = token.clone().drop_guard();
187
+
188
+ tokio::spawn({
189
+ let token = token.clone();
190
+ async move {
191
+ token.cancelled().await;
192
+ println!("Cancelled!");
193
+ }
194
+ });
195
+
196
+ drop(guard); // Automatically calls token.cancel()
197
+ ```
198
+
199
+ ## See Also
200
+
201
+ - [async-joinset-structured](./async-joinset-structured.md) - Managing multiple tasks
202
+ - [async-select-racing](./async-select-racing.md) - select! for cancellation
203
+ - [async-tokio-runtime](./async-tokio-runtime.md) - Runtime shutdown