- lib/apply/index.mjs: add STATUS_MAP to normalize platform-specific statuses to generic ones (no_button/no_submit/no_modal → skipped_no_apply). Documented all generic statuses for AI/developer reference. - job_applier.mjs: handleResult now handles skipped_no_apply, default case logs + saves instead of silently dropping - lib/linkedin.mjs: remove dead applyLinkedIn() and detectAts(), clean imports (~110 lines removed). Search-only module now. - lib/wellfound.mjs: remove dead applyWellfound(), clean imports. Search-only module now. - lib/lock.mjs: fix async signal handler — shutdown handlers now actually complete before process.exit() - test_linkedin_login.mjs: add try/catch/finally with proper browser cleanup - README: update status table with all current statuses Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
50 lines
1.5 KiB
JavaScript
50 lines
1.5 KiB
JavaScript
/**
|
|
* lock.mjs — Simple PID-based lockfile to prevent parallel runs
|
|
*/
|
|
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
import { resolve } from 'path';
|
|
|
|
export function acquireLock(name, dataDir) {
|
|
const lockFile = resolve(dataDir, `${name}.lock`);
|
|
|
|
if (existsSync(lockFile)) {
|
|
const pid = parseInt(readFileSync(lockFile, 'utf8').trim(), 10);
|
|
// Check if that process is still alive
|
|
try {
|
|
process.kill(pid, 0); // signal 0 = check existence only
|
|
console.error(`⚠️ ${name} already running (PID ${pid}). Exiting.`);
|
|
process.exit(0);
|
|
} catch {
|
|
// Stale lock — process is gone, safe to continue
|
|
console.warn(`🔓 Stale lock found (PID ${pid}), clearing.`);
|
|
}
|
|
}
|
|
|
|
writeFileSync(lockFile, String(process.pid));
|
|
|
|
// Release lock on exit (normal or crash)
|
|
const release = () => {
|
|
try { unlinkSync(lockFile); } catch {}
|
|
};
|
|
|
|
// Graceful shutdown — call registered cleanup before exiting
|
|
const shutdownHandlers = [];
|
|
const shutdown = (code) => {
|
|
console.log(`\n⚠️ ${name}: signal received, shutting down gracefully...`);
|
|
// Run handlers sequentially, then exit
|
|
(async () => {
|
|
for (const fn of shutdownHandlers) {
|
|
try { await fn(); } catch {}
|
|
}
|
|
release();
|
|
process.exit(code);
|
|
})();
|
|
};
|
|
|
|
process.on('exit', release);
|
|
process.on('SIGINT', () => shutdown(130));
|
|
process.on('SIGTERM', () => shutdown(143));
|
|
|
|
return { release, onShutdown: (fn) => shutdownHandlers.push(fn) };
|
|
}
|