Skip to content

fix: correct cleanup logic for unsubmitted forms#14

Open
mtieno wants to merge 4 commits into
vula-africa:mainfrom
mtieno:fix/unsubmitted-forms-cleanup
Open

fix: correct cleanup logic for unsubmitted forms#14
mtieno wants to merge 4 commits into
vula-africa:mainfrom
mtieno:fix/unsubmitted-forms-cleanup

Conversation

@mtieno
Copy link
Copy Markdown

@mtieno mtieno commented Sep 24, 2025

Description

Fixes critical issues in the scheduled job that cleans up unsubmitted forms older than 7 days.

Changes Made

Critical Fixes

  • Date Filtering: Now correctly identifies ALL tokens older than 7 days (was only targeting exact 7-day window)
  • Status Checking: Expanded to include all incomplete form statuses ('new', 'draft', 'in progress')
  • Transaction Order: Improved deletion sequence to prevent database constraint violations

Impact

  • Before: Only cleaned up forms exactly 7 days old, missed older abandoned forms
  • After: Comprehensive cleanup of all forms older than 7 days
  • Data Integrity: Proper deletion order prevents foreign key violations

Testing

  • Verified logic fixes address all identified issues
  • Confirmed proper date filtering and status checking
  • Validated transaction order follows database dependencies

Related Issues

Fixes logic errors in form cleanup scheduling

Checklist

  • Code follows project conventions
  • Logic fixes verified
  • Commit messages follow conventional format

Summary by CodeRabbit

  • Bug Fixes

    • Precisely targets items older than 7 days for cleanup.
    • Safely handles missing references and logs per-item errors without aborting the job.
    • Removes incomplete drafts/relationships reliably, including cases with no related records.
  • Refactor

    • Switched to per-item transactional cleanup for safer, more controlled deletions.
    • Reduced fetched data to improve efficiency.
  • Chores

    • Enhanced logging and masking for clearer monitoring and improved job status reporting.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 24, 2025

Walkthrough

Refactors unsubmitted-forms cleanup to iterate per-token with detailed logging and token masking, strict "older than 7 days" filtering, selective field retrieval, guarded handling for missing entityId, per-token transactional deletions (corpus, relationships, tokens, conditional entity delete), expanded relationship criteria, resilient per-token error handling, and final job status and completion log.

Changes

Cohort / File(s) Summary of changes
Per-token cleanup refactor
tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts
Added logging with token masking, strict < 7-day filter, select only token,entityId,productId, per-token try/catch to avoid aborting the job, delete-only-token when entityId missing, broadened relationship query to include entity_id and statuses new,draft,in_progress, replaced a single multi-step transaction with per-token transactional deletion steps (delete corpus items, delete incomplete relationships, delete tokens, delete entity only if no relationships remain), handle no-relationship case by deleting stale token, improved error logging, final completion log with processed count, minor renames/formatting.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Job as Cleanup Job
  participant DB as Database
  participant Log as Logger

  Note over Job,Log: Startup
  Job->>Log: log start (masked tokens)
  Job->>DB: Query tokens older than 7 days (select token, entityId, productId)
  DB-->>Job: Token list

  loop For each token
    Job->>Log: log token discovered (masked)
    Job->>Job: try per-token processing
    alt entityId missing
      Job->>DB: Delete token
      Job->>Log: log token-only deletion
    else entityId present
      Job->>DB: Query incomplete relationships (entity_id, status in [new,draft,in_progress])
      alt relationships found
        rect rgba(220,245,220,0.6)
        Note right of Job: Per-token transaction
        Job->>DB: Delete corpus items for entity
        Job->>DB: Delete incomplete relationships for entity
        Job->>DB: Delete tokens for entity
        Job->>DB: Delete entity if no relationships remain
        end
        Job->>Log: log cleanup success
      else no relationships
        Job->>DB: Delete stale token
        Job->>Log: log no-relationship token deletion
      end
    end
    opt error
      Job->>Log: log error (does not abort loop)
    end
  end

  Note over Job,Log: Completion
  Job->>Log: log completion with processed count
  Job->>DB: Update job status (success/failure)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I hop through tokens seven days old,
Nose to the drafts, both timid and bold.
With masked little paw I tidy the trail,
Deleting the crumbs, let the cleanups prevail.
Job logged, I bounce — carrots in my sack. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the core change—correcting the cleanup logic for unsubmitted forms—accurately reflecting the adjustments to date filtering, status checks, and deletion order. It is concise, specific, and free of unnecessary details, making the primary purpose of the PR immediately clear.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (3)

54-105: Isolate per-token failures so one bad record doesn’t abort the entire job.
Wrap the per-token work in try/catch and continue.

Apply this diff:

-    for (const token of expiredTokens) {
+    for (const token of expiredTokens) {
+      try {
         // ISSUE 2: Limited status checking
         // ORIGINAL: Only checks for "new" status
         // PROBLEM: Misses forms with other incomplete statuses like "draft", "in_progress"
         // FIX: Check for all possible incomplete statuses
-      
+        
         const relationship = await prisma.relationship.findFirst({
           where: {
             product_id: token.productId,
             // ORIGINAL (flawed): status: "new",
             // FIXED: Include all incomplete form statuses
             status: { in: ["new", "draft", "in_progress"] },
           },
         });
 
         if (relationship) {
           // ISSUE 3: Incorrect deletion order (potential foreign key constraints)
           // ORIGINAL ORDER: relationship → token → corpus → entity
           // PROBLEM: May violate foreign key constraints if entities are deleted before dependencies
           // FIX: Delete in reverse dependency order (dependencies first, parent records last)
-        
+          
           await prisma.$transaction([
             // FIXED ORDER 1: Delete corpus items first (dependencies of entity)
             prisma.new_corpus.deleteMany({
               where: {
                 entity_id: token.entityId || "",
               },
             }),
             // FIXED ORDER 2: Delete relationship (depends on product_id and entity)
             prisma.relationship.delete({
               where: { id: relationship.id },
             }),
             // FIXED ORDER 3: Delete the token (depends on productId and entityId)
             prisma.publicFormsTokens.delete({
               where: { token: token.token },
             }),
             // FIXED ORDER 4: Delete entity last (parent record)
             prisma.entity.delete({
               where: { id: token.entityId || "" },
             }),
           ]);
         
           // ISSUE 4: Missing logging for debugging and monitoring
           // ORIGINAL: No progress logging
           // FIX: Add informative logging
           console.log(`✅ Cleaned up unsubmitted form for entity: ${token.entityId}`);
         } else {
           // ORIGINAL: No logging for skipped tokens
           // FIX: Add logging for transparency
-          console.log(`➖ No incomplete relationship found for token: ${token.token}`);
+          console.log(`➖ No incomplete relationship found for token: ${token.token}`);
         }
-      }
+      } catch (e) {
+        console.error(`⚠️ Failed to clean token ${token.token}`, e);
+      }
+    }

Note: Combine with the transactional fix suggested above to remove the empty-string fallbacks.


43-52: Reduce payload: select only needed fields.
Prevents loading unused columns and improves throughput.

Apply this diff:

-    const expiredTokens = await prisma.publicFormsTokens.findMany({
-      where: {
-        createdAt: {
-          // ORIGINAL (flawed): gte: sevenDaysAgo, lt: sevenDaysAgoPlusOneDay
-          // PROBLEM: This creates a 24-hour window for exactly 7-day-old tokens only
-          // FIXED: Use 'lt' to get ALL tokens older than 7 days
-          lt: sevenDaysAgo, // LESS THAN 7 days ago (includes all older tokens)
-        },
-      },
-    });
+    const expiredTokens = await prisma.publicFormsTokens.findMany({
+      where: {
+        createdAt: { lt: sevenDaysAgo },
+      },
+      select: { token: true, entityId: true, productId: true },
+    });

If large volumes are expected, consider paginating with cursor + take to avoid long transactions.


43-52: Consider indexes to keep the job fast at scale.

  • Index publicFormsTokens.createdAt for the lt scan.
  • Index relationship on (entity_id, status).
  • Index publicFormsTokens on (entityId).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 1dd21f7 and 9ca49cb.

📒 Files selected for processing (1)
  • tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (1 hunks)
🔇 Additional comments (3)
tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (3)

41-41: Seven-days-ago calculation is now correct — LGTM.


46-50: Older-than-7-days filter is correct — LGTM.
Switching to lt: sevenDaysAgo fixes the “exactly 7 days” bug.


60-66: Verify Prisma schema definitions
Ensure:

  • the Status enum in your Prisma schema includes new, draft, and in_progress
  • the Relationship model’s fields match your code (productId vs. product_id, entityId vs. entity_id)
  • the Tokens model defines productId and entityId exactly as used here

Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts Outdated
Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts Outdated
Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts Outdated
Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts Outdated
@mtieno
Copy link
Copy Markdown
Author

mtieno commented Sep 24, 2025

Hi @GoffAC , could you please review this fix for the unsubmitted forms cleanup logic?

Summary of changes:

  • Fixed date filtering to clean up ALL forms older than 7 days (not just the exact 7-day window)
  • Expanded status checking to include all incomplete states
  • Improved transaction order to prevent database constraints

Looking forward to your review!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca49cb and e0ff045.

📒 Files selected for processing (1)
  • tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (1 hunks)

Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e0ff045 and e869ce0.

📒 Files selected for processing (1)
  • tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (1 hunks)

Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e869ce0 and f9d318b.

📒 Files selected for processing (1)
  • tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts (1 hunks)

Comment thread tests/unsubmitted_forms/cleanup_unsubmitted_forms.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant