Ver código fonte

feat: add job deduplication mechanism to prevent duplicate issue processing #16

- Added recentlyProcessed Map to track recently processed issues
- Implements 5-minute deduplication window for issue/issue_comment events
- Automatic cleanup of entries older than 10 minutes
- Prevents duplicate processing when rapid successive events occur
- Maintains zero-dependency philosophy using only Node.js built-ins

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude 9 meses atrás
pai
commit
60db3c1d5b
1 arquivos alterados com 28 adições e 1 exclusões
  1. 28 1
      src/jobQueue.js

+ 28 - 1
src/jobQueue.js

@@ -15,6 +15,9 @@ export class JobQueue {
     this.currentJob = null;
     this.jobIdCounter = 0;
 
+    // Track recently processed issue events to prevent duplicates
+    this.recentlyProcessed = new Map(); // key: "issues-15", value: timestamp
+
     // Load existing queue from file
     this.loadQueue();
   }
@@ -76,9 +79,33 @@ export class JobQueue {
    * @param {object} payload - The webhook payload
    * @param {object} headers - The webhook headers
    * @param {object} config - The command configuration
-   * @returns {object} The created job
+   * @returns {object|null} The created job or null if duplicate
    */
   enqueue(eventType, payload, headers, config) {
+    // For issue events, check if we processed this recently (within 5 minutes)
+    if (eventType === 'issues' || eventType === 'issue_comment') {
+      const issueNumber = payload.issue?.number;
+      if (issueNumber) {
+        const key = `issue-${issueNumber}`;
+        const lastProcessed = this.recentlyProcessed.get(key);
+        const now = Date.now();
+
+        if (lastProcessed && (now - lastProcessed < 300000)) { // 5 minutes
+          logger.info(`Skipping duplicate job for ${key} (processed ${Math.round((now - lastProcessed)/1000)}s ago)`);
+          return null;
+        }
+
+        this.recentlyProcessed.set(key, now);
+
+        // Cleanup old entries (older than 10 minutes)
+        for (const [k, ts] of this.recentlyProcessed.entries()) {
+          if (now - ts > 600000) {
+            this.recentlyProcessed.delete(k);
+          }
+        }
+      }
+    }
+
     const job = {
       id: ++this.jobIdCounter,
       eventType,