| 181 | } |
| 182 | |
| 183 | async fn run_watchdog(port: u16) { |
| 184 | let mut watchdog_usec = 0; |
| 185 | let enabled = sd_notify::watchdog_enabled(false, &mut watchdog_usec); |
| 186 | if !enabled { |
| 187 | info!("Watchdog is not enabled in systemd service"); |
| 188 | return pending::<()>().await; |
| 189 | } |
| 190 | |
| 191 | info!("Starting watchdog"); |
| 192 | if let Err(err) = sd_notify(false, &[NotifyState::Ready]) { |
| 193 | error!("Failed to notify systemd: {err}"); |
| 194 | } |
| 195 | let heatbeat_interval = Duration::from_micros(watchdog_usec / 2); |
| 196 | let heatbeat_interval = heatbeat_interval.max(Duration::from_secs(1)); |
| 197 | info!("Watchdog enabled, interval={watchdog_usec}us, heartbeat={heatbeat_interval:?}"); |
| 198 | let mut interval = tokio::time::interval(heatbeat_interval); |
| 199 | |
| 200 | let probe_url = format!("http://localhost:{port}/prpc/Worker.Version"); |
| 201 | loop { |
| 202 | interval.tick().await; |
| 203 | |
| 204 | let client = reqwest::Client::new(); |
| 205 | match client.get(&probe_url).send().await { |
| 206 | Ok(response) if response.status().is_success() => { |
| 207 | if let Err(err) = sd_notify(false, &[NotifyState::Watchdog]) { |
| 208 | error!("Failed to notify systemd: {err}"); |
| 209 | } |
| 210 | } |
| 211 | Ok(response) => { |
| 212 | error!("Health check failed with status: {}", response.status()); |
| 213 | } |
| 214 | Err(err) => { |
| 215 | error!("Health check request failed: {err:?}"); |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | pub async fn run(state: AppState, figment: Figment, watchdog: bool) -> Result<()> { |
| 222 | let internal_v0_figment = figment.clone().select("internal-v0"); |