fix: prevent false-positive 'Session lock lost' during auto-mode (#1257)
- Add onCompromised handler to prevent uncaught throw in setTimeout - Increase stale threshold from 5min to 30min for laptop sleep safety - Release OS lock explicitly in SIGTERM handler
This commit is contained in:
parent
b095e352a7
commit
ad9d7a1815
2 changed files with 21 additions and 1 deletions
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { clearLock } from "./crash-recovery.js";
|
||||
import { releaseSessionLock } from "./session-lock.js";
|
||||
import { nativeHasChanges } from "./native-git-bridge.js";
|
||||
|
||||
// ─── SIGTERM Handling ─────────────────────────────────────────────────────────
|
||||
|
|
@ -23,6 +24,7 @@ export function registerSigtermHandler(
|
|||
): () => void {
|
||||
if (previousHandler) process.off("SIGTERM", previousHandler);
|
||||
const handler = () => {
|
||||
releaseSessionLock(currentBasePath);
|
||||
clearLock(currentBasePath);
|
||||
process.exit(0);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ let _lockedPath: string | null = null;
|
|||
/** Our PID at lock acquisition time. */
|
||||
let _lockPid: number = 0;
|
||||
|
||||
/** Set to true when proper-lockfile fires onCompromised (mtime drift, sleep, etc.). */
|
||||
let _lockCompromised: boolean = false;
|
||||
|
||||
const LOCK_FILE = "auto.lock";
|
||||
|
||||
function lockPath(basePath: string): string {
|
||||
|
|
@ -102,13 +105,22 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
|
|||
|
||||
const release = lockfile.lockSync(gsdDir, {
|
||||
realpath: false,
|
||||
stale: 300_000, // 5 minutes — consider lock stale if holder hasn't updated
|
||||
stale: 1_800_000, // 30 minutes — safe for laptop sleep / long event loop stalls
|
||||
update: 10_000, // Update lock mtime every 10s to prove liveness
|
||||
onCompromised: () => {
|
||||
// proper-lockfile detected mtime drift (system sleep, event loop stall, etc.).
|
||||
// Default handler throws inside setTimeout — an uncaught exception that crashes
|
||||
// or corrupts process state. Instead, set a flag so validateSessionLock() can
|
||||
// detect the compromise gracefully on the next dispatch cycle.
|
||||
_lockCompromised = true;
|
||||
_releaseFunction = null;
|
||||
},
|
||||
});
|
||||
|
||||
_releaseFunction = release;
|
||||
_lockedPath = basePath;
|
||||
_lockPid = process.pid;
|
||||
_lockCompromised = false;
|
||||
|
||||
// Safety net: clean up lock dir on process exit if _releaseFunction
|
||||
// wasn't called (e.g., normal exit after clean completion) (#1245).
|
||||
|
|
@ -233,6 +245,11 @@ export function updateSessionLock(
|
|||
* This is called periodically during the dispatch loop.
|
||||
*/
|
||||
export function validateSessionLock(basePath: string): boolean {
|
||||
// Lock was compromised by proper-lockfile (mtime drift from sleep, stall, etc.)
|
||||
if (_lockCompromised) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have an OS-level lock, we're still the owner
|
||||
if (_releaseFunction && _lockedPath === basePath) {
|
||||
return true;
|
||||
|
|
@ -284,6 +301,7 @@ export function releaseSessionLock(basePath: string): void {
|
|||
|
||||
_lockedPath = null;
|
||||
_lockPid = 0;
|
||||
_lockCompromised = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue