mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(auth): let profile locks reach stale reclaim
This commit is contained in:
@@ -13,7 +13,6 @@ const CURRENT_SCHEMA_VERSION: u32 = 1;
|
||||
const PROFILES_FILENAME: &str = "auth-profiles.json";
|
||||
const LOCK_FILENAME: &str = "auth-profiles.lock";
|
||||
const LOCK_WAIT_MS: u64 = 50;
|
||||
const LOCK_TIMEOUT_MS: u64 = 10_000;
|
||||
/// A lock file that has existed for longer than this is treated as leaked
|
||||
/// (its owner crashed without unlinking it, or `fs::remove_file` in the
|
||||
/// guard's `Drop` was rejected by Windows AV/indexer and the file got
|
||||
@@ -23,6 +22,9 @@ const LOCK_TIMEOUT_MS: u64 = 10_000;
|
||||
/// threshold is intentionally well above any realistic operation time
|
||||
/// so we never reclaim under a slow-but-legitimate holder.
|
||||
const STALE_LOCK_AGE_MS: u64 = 30_000;
|
||||
/// Wait long enough for a fresh leaked lock to cross the stale threshold
|
||||
/// and be reclaimed before surfacing a lock timeout to the caller.
|
||||
const LOCK_TIMEOUT_MS: u64 = STALE_LOCK_AGE_MS + 5_000;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
@@ -595,7 +597,7 @@ impl AuthProfilesStore {
|
||||
// Issue #1612 — a previous openhuman crash can leave a
|
||||
// stale auth-profiles.lock behind, after which every RPC
|
||||
// path that touches the auth profile store fails for the
|
||||
// 10s LOCK_TIMEOUT_MS window and the user gets stuck in a
|
||||
// `LOCK_TIMEOUT_MS` window and the user gets stuck in a
|
||||
// retry storm. Before falling back to the busy-wait, try
|
||||
// once to peek at the writer's recorded PID and remove
|
||||
// the lock if that process is no longer alive. Flag is
|
||||
@@ -654,7 +656,7 @@ impl AuthProfilesStore {
|
||||
/// `AuthProfileLockGuard::drop` could not unlink the file (AV /
|
||||
/// indexer briefly held a handle) and orphaned the lock with its
|
||||
/// still-alive pid inside — every subsequent acquirer would
|
||||
/// otherwise spin the full 10s `LOCK_TIMEOUT_MS` and bail. No
|
||||
/// otherwise spin the full `LOCK_TIMEOUT_MS` and bail. No
|
||||
/// legitimate auth-profile op holds the lock long enough to be
|
||||
/// affected, so a too-old lock is unambiguously a leak.
|
||||
///
|
||||
|
||||
@@ -495,6 +495,18 @@ fn clear_lock_if_stale_reclaims_aged_malformed_lock() {
|
||||
assert!(!lock_path.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lock_timeout_allows_fresh_leaked_locks_to_age_into_stale_reclaim() {
|
||||
assert!(
|
||||
LOCK_TIMEOUT_MS > STALE_LOCK_AGE_MS,
|
||||
"lock timeout must outlive stale-lock age so a fresh leaked lock can be reclaimed"
|
||||
);
|
||||
assert!(
|
||||
LOCK_TIMEOUT_MS - STALE_LOCK_AGE_MS >= 1_000,
|
||||
"timeout should leave at least one periodic stale recheck after the threshold"
|
||||
);
|
||||
}
|
||||
|
||||
/// Sentry OPENHUMAN-TAURI-H8: when `OpenOptions::create_new` fails with
|
||||
/// anything other than `AlreadyExists`, the error surfaced to Sentry
|
||||
/// must embed the underlying `io::ErrorKind` and `raw_os_error()` so we
|
||||
|
||||
Reference in New Issue
Block a user