Skip to content

Commit 12f24a4

Browse files
authored
Create cleanupOrphanedWorkflowContexts.js
Added cleanupOrphanedWorkflowContexts.js file with the script that Identifies and cancels stale or orphaned workflow contexts stuck in the “Executing” state for extended periods to maintain system health.
1 parent 6e1637b commit 12f24a4

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Fix Script: Cleanup Orphaned and Stale Workflow Contexts
2+
// Purpose: Cancel and clean up workflow contexts that are:
3+
// 1. In "Executing" state for more than 180 days
4+
// 2. Associated with deleted/invalid parent records
5+
// 3. Stuck without valid activity states
6+
//
7+
// Author: Masthan Sharif Shaik
8+
// Date: October 2025
9+
// Tested on: Zurich, Yokohama
10+
//
11+
// IMPORTANT: Test in non-production environment first
12+
// This script will mark stale workflows as cancelled and prevent re-execution
13+
14+
(function cleanupOrphanedWorkflowContexts() {
15+
16+
// Configuration - adjust these values based on your requirements
17+
var DAYS_THRESHOLD = 180; // Workflows executing longer than this will be evaluated
18+
var BATCH_SIZE = 500; // Process in batches to avoid transaction timeouts
19+
var DRY_RUN = true; // Set to false to actually cancel workflows
20+
21+
// Calculate date threshold
22+
var thresholdDate = new GlideDateTime();
23+
thresholdDate.addDaysLocalTime(-DAYS_THRESHOLD);
24+
25+
var totalProcessed = 0;
26+
var totalCancelled = 0;
27+
var orphanedCount = 0;
28+
29+
gs.info('=== Workflow Context Cleanup Started ===');
30+
gs.info('Threshold Date: ' + thresholdDate.getDisplayValue());
31+
gs.info('Dry Run Mode: ' + DRY_RUN);
32+
33+
// Query for stale executing workflow contexts
34+
var wfContext = new GlideRecord('wf_context');
35+
wfContext.addQuery('state', 'executing');
36+
wfContext.addQuery('sys_created_on', '<', thresholdDate);
37+
wfContext.setLimit(BATCH_SIZE);
38+
wfContext.query();
39+
40+
gs.info('Found ' + wfContext.getRowCount() + ' stale workflow contexts to process');
41+
42+
while (wfContext.next()) {
43+
totalProcessed++;
44+
var shouldCancel = false;
45+
var reason = '';
46+
47+
// Check if parent record exists
48+
var tableName = wfContext.getValue('table');
49+
var recordId = wfContext.getValue('id');
50+
51+
if (!tableName || !recordId) {
52+
shouldCancel = true;
53+
reason = 'Missing table or record reference';
54+
orphanedCount++;
55+
} else {
56+
// Verify parent record exists
57+
var parentRecord = new GlideRecord(tableName);
58+
if (!parentRecord.get(recordId)) {
59+
shouldCancel = true;
60+
reason = 'Parent record no longer exists';
61+
orphanedCount++;
62+
}
63+
}
64+
65+
66+
if (shouldCancel) {
67+
gs.info('Context: ' + wfContext.getDisplayValue() +
68+
' | Age: ' + wfContext.sys_created_on.getDisplayValue() +
69+
' | Reason: ' + reason);
70+
71+
if (!DRY_RUN) {
72+
// Cancel the workflow context
73+
wfContext.state = 'cancelled';
74+
wfContext.setWorkflow(false); // Prevent additional workflows from triggering
75+
wfContext.update();
76+
totalCancelled++;
77+
}
78+
}
79+
}
80+
81+
gs.info('=== Workflow Context Cleanup Complete ===');
82+
gs.info('Total Processed: ' + totalProcessed);
83+
gs.info('Orphaned Workflows Found: ' + orphanedCount);
84+
gs.info('Workflows Cancelled: ' + (DRY_RUN ? '0 (Dry Run)' : totalCancelled));
85+
gs.info('To execute cleanup, set DRY_RUN = false');
86+
87+
})();

0 commit comments

Comments
 (0)