Skip to main content

headless_lms_credit_registration/runtime/
heartbeat.rs

1//! The heartbeat a running iteration keeps refreshing.
2
3use headless_lms_models::credit_registration_phase_state;
4use sqlx::PgPool;
5use std::convert::Infallible;
6use std::time::Duration;
7use tokio::time::MissedTickBehavior;
8
9use crate::error::CreditRegistrationResult;
10use crate::phase::CreditRegistrationPhase;
11
12/// How often a running iteration refreshes its heartbeat. Under half the shortest phase interval,
13/// so even the 10-second phases never read as stale mid-call.
14const KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(5);
15
16/// Refreshes one phase's heartbeat until dropped, so a long study registry call does not raise the
17/// stale-worker alert.
18pub(super) async fn keep_alive(pool: &PgPool, phase: CreditRegistrationPhase) -> Infallible {
19    let mut interval = tokio::time::interval(KEEP_ALIVE_INTERVAL);
20    interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
21    loop {
22        interval.tick().await;
23        let refreshed = async {
24            let mut conn = pool.acquire().await?;
25            credit_registration_phase_state::keep_alive(&mut conn, phase.as_str()).await?;
26            CreditRegistrationResult::Ok(())
27        }
28        .await;
29        match refreshed {
30            Ok(()) => trace!(phase = phase.as_str(), "Refreshed phase heartbeat"),
31            Err(error) => {
32                warn!(phase = phase.as_str(), error = %error, "Failed to refresh phase heartbeat");
33            }
34        }
35    }
36}