mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 08:01:25 +00:00
fd41cd12b4
* fix: improve OOM killer observability for debugging pod-level kills Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: lower worker oom_score_adj to protect it from OOM killer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review feedback on OOM observability Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
3.7 KiB
Rust
115 lines
3.7 KiB
Rust
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug)]
|
|
pub enum CgroupError {
|
|
#[allow(unused)]
|
|
PathNotFound(PathBuf),
|
|
NotSupported,
|
|
PermissionDenied,
|
|
#[allow(unused)]
|
|
Io(std::io::Error),
|
|
}
|
|
|
|
impl From<std::io::Error> for CgroupError {
|
|
fn from(e: std::io::Error) -> Self {
|
|
CgroupError::Io(e)
|
|
}
|
|
}
|
|
|
|
pub fn get_cgroup_path() -> Result<PathBuf, CgroupError> {
|
|
let cgroup_info = fs::read_to_string("/proc/1/cgroup")?;
|
|
|
|
// Format: "0::/kubepods.slice/..." - we want the part after the second colon
|
|
let cgroup_rel = cgroup_info
|
|
.lines()
|
|
.next()
|
|
.and_then(|line| line.splitn(3, ':').nth(2))
|
|
.unwrap_or("")
|
|
.trim();
|
|
|
|
let cgroup_path = PathBuf::from(format!("/sys/fs/cgroup{}", cgroup_rel));
|
|
|
|
if !cgroup_path.is_dir() {
|
|
return Err(CgroupError::PathNotFound(cgroup_path));
|
|
}
|
|
|
|
Ok(cgroup_path)
|
|
}
|
|
|
|
pub fn disable_oom_group() -> Result<(), CgroupError> {
|
|
let cgroup_path = get_cgroup_path()?;
|
|
let oom_group_file = cgroup_path.join("memory.oom.group");
|
|
|
|
if !oom_group_file.exists() {
|
|
tracing::warn!(
|
|
"memory.oom.group not found at {:?} — cgroups v2 memory controller may not be enabled. \
|
|
OOM killer may kill the entire pod instead of individual jobs",
|
|
oom_group_file
|
|
);
|
|
return Err(CgroupError::NotSupported);
|
|
}
|
|
|
|
let current = fs::read_to_string(&oom_group_file)?;
|
|
if current.trim() == "0" {
|
|
tracing::info!("memory.oom.group already disabled at {:?}", cgroup_path);
|
|
return Ok(());
|
|
}
|
|
|
|
tracing::info!(
|
|
"memory.oom.group is currently '{}' at {:?}, attempting to disable",
|
|
current.trim(),
|
|
cgroup_path
|
|
);
|
|
|
|
match fs::write(&oom_group_file, "0") {
|
|
Ok(_) => {
|
|
// Verify the write took effect
|
|
match fs::read_to_string(&oom_group_file) {
|
|
Ok(val) if val.trim() == "0" => {
|
|
tracing::info!("Disabled memory.oom.group at {:?}", cgroup_path);
|
|
}
|
|
Ok(val) => {
|
|
tracing::error!(
|
|
"Wrote 0 to memory.oom.group but read back '{}' at {:?}. \
|
|
OOM killer may kill the entire pod instead of individual jobs",
|
|
val.trim(),
|
|
cgroup_path
|
|
);
|
|
return Err(CgroupError::Io(std::io::Error::new(
|
|
std::io::ErrorKind::Other,
|
|
format!(
|
|
"memory.oom.group write did not take effect, read back '{}'",
|
|
val.trim()
|
|
),
|
|
)));
|
|
}
|
|
Err(e) => {
|
|
tracing::warn!(
|
|
"Wrote 0 to memory.oom.group but could not verify at {:?}: {e}",
|
|
cgroup_path
|
|
);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
|
|
tracing::error!(
|
|
"Failed to disable memory.oom.group at {:?} (permission denied). \
|
|
The container needs SYS_RESOURCE capability or privileged mode. \
|
|
OOM killer WILL kill the entire pod instead of individual jobs",
|
|
oom_group_file
|
|
);
|
|
Err(CgroupError::PermissionDenied)
|
|
}
|
|
Err(e) => {
|
|
tracing::error!(
|
|
"Failed to disable memory.oom.group at {:?}: {e}. \
|
|
OOM killer may kill the entire pod instead of individual jobs",
|
|
oom_group_file
|
|
);
|
|
Err(CgroupError::Io(e))
|
|
}
|
|
}
|
|
}
|