use {
crate::{
Partitions,
database::chunk::RecordWriter,
protocol::lsp::LanguageServer,
scheduler::task::TaskContext,
},
std::{
future::Future,
pin::Pin,
sync::{
Arc,
atomic::{
AtomicBool,
Ordering,
},
},
time::Duration,
},
};
type IdleMonitorTaskFn<P, T> = Box<
dyn FnOnce(
TaskContext<P, T>,
) -> Pin<Box<dyn Future<Output = Option<RecordWriter<P>>> + Send>>
+ Send
+ 'static,
>;
const POLL_INTERVAL: Duration = Duration::from_secs(1);
pub(crate) fn idle_monitor_task<P: Partitions, T: LanguageServer<P>>(
shutdown_flag: Arc<AtomicBool>,
idle_triggered: Arc<AtomicBool>,
idle_timeout: Duration,
) -> IdleMonitorTaskFn<P, T> {
Box::new(move |ctx| {
Box::pin({
let scheduler = ctx.scheduler();
async move {
loop {
smol::Timer::after(POLL_INTERVAL).await;
if shutdown_flag.load(Ordering::Acquire) {
return None;
}
let registry = scheduler.registry();
if registry.client_count() != 0 {
continue;
}
let Some(idle) = registry.idle_duration() else {
continue;
};
if idle < idle_timeout {
continue;
}
otel::event!(
"daemon_idle_monitor_trigger",
"idle_seconds" = idle.as_secs() as i64,
"timeout_seconds" = idle_timeout.as_secs() as i64
);
idle_triggered.store(true, Ordering::Release);
scheduler.request_shutdown();
return None;
}
}
})
})
}