feat: add in-process mutex to prevent concurrent scraper runs
All checks were successful
CI/CD Pipeline - Apartment API / Scan Dependencies (pull_request) Successful in 13s
CI/CD Pipeline - Apartment API / Lint & Test (pull_request) Successful in 38s
CI/CD Pipeline - Apartment API / Send Webhook Notification (pull_request) Successful in 2s
CI/CD Pipeline - Apartment API / Build & Push Image (pull_request) Has been skipped
CI/CD Pipeline - Apartment API / Deploy to Production (pull_request) Has been skipped

Implement a lightweight in-process mutex lock for the scraper job
scheduler. This prevents multiple scraper instances from running
simultaneously, which could cause duplicate data and race conditions.

Exported functions:
- acquireLock(jobId): Attempts to acquire the mutex, returns boolean
- releaseLock(): Releases the mutex lock
- isScraperRunning(): Returns current lock state
- getCurrentJobId(): Returns the active job ID or null

Includes 19 unit tests covering lock acquisition, release, re-entry
prevention, and edge cases.
This commit is contained in:
2026-02-06 16:25:37 -07:00
parent d818296eeb
commit df86a1423c
2 changed files with 199 additions and 0 deletions

48
jobs/scraperJob.js Normal file
View File

@ -0,0 +1,48 @@
// In-process mutex state
let isRunning = false;
let currentJobId = null;
/**
* Check if scraper is currently running
* @returns {boolean}
*/
function isScraperRunning() {
return isRunning;
}
/**
* Get current job ID if running
* @returns {string|null}
*/
function getCurrentJobId() {
return currentJobId;
}
/**
* Acquire the scraper lock
* @param {string} jobId - Job ID to set
* @returns {boolean} True if lock acquired
*/
function acquireLock(jobId) {
if (isRunning) {
return false;
}
isRunning = true;
currentJobId = jobId;
return true;
}
/**
* Release the scraper lock
*/
function releaseLock() {
isRunning = false;
currentJobId = null;
}
module.exports = {
isScraperRunning,
getCurrentJobId,
acquireLock,
releaseLock
};