Problem
When an assessment is deleted, any pending or active BullMQ jobs for that assessment (`fileIndex--N`, `gapAnalysis-`) are not cleaned up. They remain in the queue and continue to hold Redis lock keys.
This causes:
- Worker lock-renewal errors every 2 minutes (`could not renew lock for job fileIndex-:lock`) flooding the logs
- Queue counts showing phantom "active" jobs that are actually orphaned
- Confusion when diagnosing real stuck jobs vs zombie jobs
Observed in prod after the SOC-2 assessment was deleted: lock errors persisted for days until manually flushed.
Fix
In the assessment delete handler (`AssessmentService.js` or the route), after removing the MongoDB document:
- Remove all BullMQ jobs matching the assessment ID pattern from `assessmentQueue`
- Delete their Redis lock keys (`bull:assessmentJobs::lock`)
```js
// pseudo-code
const jobIds = documents.map((_, i) => `fileIndex-${assessmentId}-${i}`);
jobIds.push(`gapAnalysis-${assessmentId}`);
for (const jobId of jobIds) {
const lockKey = `bull:assessmentJobs:${jobId}:lock`;
await redis.del(lockKey);
const job = await assessmentQueue.getJob(jobId);
await job?.remove();
}
```
Problem
When an assessment is deleted, any pending or active BullMQ jobs for that assessment (`fileIndex--N`, `gapAnalysis-`) are not cleaned up. They remain in the queue and continue to hold Redis lock keys.
This causes:
Observed in prod after the SOC-2 assessment was deleted: lock errors persisted for days until manually flushed.
Fix
In the assessment delete handler (`AssessmentService.js` or the route), after removing the MongoDB document:
```js
// pseudo-code
const jobIds = documents.map((_, i) => `fileIndex-${assessmentId}-${i}`);
jobIds.push(`gapAnalysis-${assessmentId}`);
for (const jobId of jobIds) {
const lockKey = `bull:assessmentJobs:${jobId}:lock`;
await redis.del(lockKey);
const job = await assessmentQueue.getJob(jobId);
await job?.remove();
}
```