|
1 | 1 | use chrono::{DateTime, Utc}; |
| 2 | +use futures::FutureExt; |
2 | 3 | use snafu::{ResultExt, Snafu}; |
3 | 4 | use stackable_shared::time::Duration; |
| 5 | +use tokio::select; |
4 | 6 | use tracing::{Level, instrument}; |
5 | 7 |
|
6 | 8 | /// Available options to configure a [`EndOfSupportChecker`]. |
@@ -114,33 +116,51 @@ impl EndOfSupportChecker { |
114 | 116 | /// |
115 | 117 | /// It is recommended to run the end-of-support checker via [`futures::try_join!`] or |
116 | 118 | /// [`tokio::join`] alongside other futures (eg. for controllers). |
117 | | - pub async fn run(self) { |
| 119 | + pub async fn run<F>(self, shutdown_signal: F) |
| 120 | + where |
| 121 | + F: Future<Output = ()>, |
| 122 | + { |
118 | 123 | // Immediately return if the end-of-support checker is disabled. |
119 | 124 | if self.disabled { |
120 | 125 | return; |
121 | 126 | } |
122 | 127 |
|
123 | | - // Construct an interval which can be polled. |
124 | 128 | let mut interval = tokio::time::interval(self.interval.into()); |
125 | 129 |
|
| 130 | + let shutdown_signal = shutdown_signal.fuse(); |
| 131 | + tokio::pin!(shutdown_signal); |
| 132 | + |
126 | 133 | loop { |
127 | | - // TODO: Add way to stop from the outside |
128 | | - // The first tick ticks immediately. |
129 | | - interval.tick().await; |
130 | | - let now = Utc::now(); |
131 | | - |
132 | | - tracing::info_span!( |
133 | | - "checking end-of-support state", |
134 | | - eos.interval = self.interval.to_string(), |
135 | | - eos.now = now.to_rfc3339(), |
136 | | - ); |
137 | | - |
138 | | - // Continue the loop and wait for the next tick to run the check again. |
139 | | - if now <= self.eos_datetime { |
140 | | - continue; |
| 134 | + select! { |
| 135 | + // We used a biased polling strategy to always check if a |
| 136 | + // shutdown signal was received before polling the EoS check |
| 137 | + // interval. |
| 138 | + biased; |
| 139 | + |
| 140 | + _ = &mut shutdown_signal => { |
| 141 | + tracing::trace!("received shutdown signal"); |
| 142 | + break; |
| 143 | + } |
| 144 | + |
| 145 | + // The first tick ticks immediately. |
| 146 | + _ = interval.tick() => { |
| 147 | + let now = Utc::now(); |
| 148 | + |
| 149 | + tracing::info_span!( |
| 150 | + "checking end-of-support state", |
| 151 | + eos.interval = self.interval.to_string(), |
| 152 | + eos.now = now.to_rfc3339(), |
| 153 | + ); |
| 154 | + |
| 155 | + // Continue the loop and wait for the next tick to run the |
| 156 | + // check again. |
| 157 | + if now <= self.eos_datetime { |
| 158 | + continue; |
| 159 | + } |
| 160 | + |
| 161 | + self.emit_warning(now); |
| 162 | + } |
141 | 163 | } |
142 | | - |
143 | | - self.emit_warning(now); |
144 | 164 | } |
145 | 165 | } |
146 | 166 |
|
|
0 commit comments