You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Background worker panics on io_uring init failure (Fargate / seccomp-restricted Linux) instead of falling back #25
On any Linux environment where io_uring is unavailable — AWS Fargate, AWS
Lambda, gVisor, or a Docker seccomp profile that denies io_uring_setup —
walrus-rust 0.2.0 panics its background flush/cleanup worker thread. The README
documents io_uring as an optional acceleration with fallbacks, but the
implementation hard-.expect()s on it.
Environment
walrus-rust 0.2.0 (crates.io)
Linux container on AWS Fargate (platform seccomp policy denies io_uring syscalls)
What happens
Walrus::with_consistency(ReadConsistency::AtLeastOnce { persist_every: 100 })
spawns the background worker, which immediately panics:
thread '' panicked at src/wal/runtime/background.rs:43:53:
Failed to create io_uring: Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }
src/wal/runtime/background.rs:43:
#[cfg(target_os = "linux")]letmut ring = io_uring::IoUring::new(2048).expect("Failed to create io_uring");
This runs unconditionally when the background worker starts (only
#[cfg(target_os = "linux")]-gated). The panic kills the whole flush + cleanup
thread, so periodic fsync and WAL file compaction/deletion silently stop.
Walrus::new() itself still returns Ok, so the failure is silent — the WAL
looks healthy while its background maintenance is dead.
Why this is a bug
The README frames io_uring as optional ("io_uring acceleration on Linux";
"disable_fd_backend() switches to the mmap backend"; "other platforms fall
back to sequential writes"). io_uring is genuinely absent in many standard
environments, so it shouldn't be assumed present on Linux. The fallback
machinery already exists — USE_FD_BACKEND / disable_fd_backend() and the
non-io_uring flush path in the same function. The worker just never engages it
on init failure; and disable_fd_backend() doesn't help because line 43 runs
before/independent of the USE_FD_BACKEND check.
Suggested fix
Make IoUring::new() failure fall back instead of panicking:
#[cfg(target_os = "linux")]letmut ring = match io_uring::IoUring::new(2048){Ok(r) => Some(r),Err(e) => {eprintln!("walrus: io_uring unavailable ({e}); using blocking fsync fallback");crate::wal::config::disable_fd_backend();None}};
then gate the io_uring submission block on ring.as_mut() (the if USE_FD_BACKEND branch is already skipped once disable_fd_backend() is called).
changed the title [-]Background worker panics on io_uring init failure (Fargate / seccomp-restricted Linux) instead of falling back ## Summary[/-][+]Background worker panics on io_uring init failure (Fargate / seccomp-restricted Linux) instead of falling back[/+]on May 21, 2026
Yeah confirmed, I took a quick look and that's the only io_uring site that panics. writer and reader already fall back, and the non io_uring branch right below at line 145 works on both backends, so the fix is basically what you've drafted. PR very welcome.
One heads up before you write it: disable_fd_backend() also flips the Fd vs Mmap storage choice, so calling it from the worker thread races with startup_chore() on the main thread and you can end up with some blocks Fd backed and others Mmap backed in the same instance. it's still functionally fine since SharedMmap dispatches either way, but if you'd rather not change storage behavior as a side effect, a local Option<IoUring> with ring.as_mut() gating keeps the fix scoped to just this thread. either way works, send whichever feels cleaner to you.
Activity
[-]Background worker panics on io_uring init failure (Fargate / seccomp-restricted Linux) instead of falling back ## Summary[/-][+]Background worker panics on io_uring init failure (Fargate / seccomp-restricted Linux) instead of falling back[/+]nubskr commentedon May 24, 2026
Yeah confirmed, I took a quick look and that's the only io_uring site that panics. writer and reader already fall back, and the non io_uring branch right below at line 145 works on both backends, so the fix is basically what you've drafted. PR very welcome.
One heads up before you write it:
disable_fd_backend()also flips the Fd vs Mmap storage choice, so calling it from the worker thread races withstartup_chore()on the main thread and you can end up with some blocks Fd backed and others Mmap backed in the same instance. it's still functionally fine sinceSharedMmapdispatches either way, but if you'd rather not change storage behavior as a side effect, a localOption<IoUring>withring.as_mut()gating keeps the fix scoped to just this thread. either way works, send whichever feels cleaner to you.