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 PROFILES_FILENAME: &str = "auth-profiles.json";
|
||||||
const LOCK_FILENAME: &str = "auth-profiles.lock";
|
const LOCK_FILENAME: &str = "auth-profiles.lock";
|
||||||
const LOCK_WAIT_MS: u64 = 50;
|
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
|
/// 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
|
/// (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
|
/// 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
|
/// threshold is intentionally well above any realistic operation time
|
||||||
/// so we never reclaim under a slow-but-legitimate holder.
|
/// so we never reclaim under a slow-but-legitimate holder.
|
||||||
const STALE_LOCK_AGE_MS: u64 = 30_000;
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
@@ -595,7 +597,7 @@ impl AuthProfilesStore {
|
|||||||
// Issue #1612 — a previous openhuman crash can leave a
|
// Issue #1612 — a previous openhuman crash can leave a
|
||||||
// stale auth-profiles.lock behind, after which every RPC
|
// stale auth-profiles.lock behind, after which every RPC
|
||||||
// path that touches the auth profile store fails for the
|
// 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
|
// retry storm. Before falling back to the busy-wait, try
|
||||||
// once to peek at the writer's recorded PID and remove
|
// once to peek at the writer's recorded PID and remove
|
||||||
// the lock if that process is no longer alive. Flag is
|
// 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 /
|
/// `AuthProfileLockGuard::drop` could not unlink the file (AV /
|
||||||
/// indexer briefly held a handle) and orphaned the lock with its
|
/// indexer briefly held a handle) and orphaned the lock with its
|
||||||
/// still-alive pid inside — every subsequent acquirer would
|
/// 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
|
/// legitimate auth-profile op holds the lock long enough to be
|
||||||
/// affected, so a too-old lock is unambiguously a leak.
|
/// 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());
|
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
|
/// Sentry OPENHUMAN-TAURI-H8: when `OpenOptions::create_new` fails with
|
||||||
/// anything other than `AlreadyExists`, the error surfaced to Sentry
|
/// anything other than `AlreadyExists`, the error surfaced to Sentry
|
||||||
/// must embed the underlying `io::ErrorKind` and `raw_os_error()` so we
|
/// must embed the underlying `io::ErrorKind` and `raw_os_error()` so we
|
||||||
|
|||||||
Reference in New Issue
Block a user