Auto-reminder and auto-close after 10 business days for pending approvals and On Hold tickets
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-26-2026 11:51 PM
Hi All,
I have a requirement to implement a scheduled job in ServiceNow for both Incidents and Request Items (RITMs) with the following logic:
Requirement:
- For records in:
- Pending Approval
- On Hold
- The system should:
- Send reminders during the 10 business days
- If no action is taken within 10 business days, then:
- Auto-close the ticket
Business Rules:
- Business days = Sunday to Thursday
- Exclude weekends (Friday & Saturday)
- Exclude holidays (defined in schedule)
- Applies to:
- Incident
- sc_req_item (RITM)
Current Approach:
- I initially implemented a loop-based logic to calculate business days by excluding weekends
- However, this does not handle holidays
- I am now considering using GlideSchedule to:
- Calculate business duration
- Handle holidays properly
Challenges:
- How to accurately calculate 10 business days including holidays
- How to design reminder logic within those 10 days
- Ensuring performance efficiency in a scheduled job (avoiding heavy loops per record)
- Applying the same logic consistently across Incident and RITM
Scheduled job:// ================= DAY CHECK =================var gdtToday = new GlideDateTime();gdtToday.setStartOfDay();var day = parseInt(gdtToday.getDayOfWeekLocalTime(), 10);// Run only Sunday–Thursdayif (day != 5 && day != 6) {// ================= CALCULATE 10 BUSINESS DAYS =================var count = 0;var pastDate = new GlideDateTime(gdtToday);while (count < 10) {pastDate.addDaysLocalTime(-1);var d = parseInt(pastDate.getDayOfWeekLocalTime(), 10);// Skip Friday (5) and Saturday (6)if (d != 5 && d != 6) {count++;}}// VERY IMPORTANT → include full daypastDate.setDisplayValue(pastDate.getLocalDate() + " 23:59:59");gs.info("Auto-close running. Cutoff date: " + pastDate.getDisplayValue());// ================= INCIDENT =================var appr = new GlideRecord('incident');appr.addQuery('active', true);appr.addQuery('state', 3);appr.addQuery('sys_updated_on', '<=', pastDate);appr.addQuery('hold_reason', '6');appr.query();var incidentCount = 0;while (appr.next()) {gs.eventQueue('autocancel.incident', appr, "", "");appr.state = '8';appr.sys_updated_by = 'system';appr.comments = "This ticket has been automatically closed due to no activity over the past 10 business days (Sun–Thu). On Hold Reason: " + appr.getDisplayValue('hold_reason');appr.update();incidentCount++;}// ================= RITM =================var gr_SRonhold = new GlideRecord('sc_req_item');gr_SRonhold.addQuery('active', true);gr_SRonhold.addQuery('state', 17);gr_SRonhold.addQuery('sys_updated_on', '<=', pastDate);gr_SRonhold.addQuery('u_on_hold_reason', '2');gr_SRonhold.query();var ritmCount = 0;while (gr_SRonhold.next()) {var ritmSysId = gr_SRonhold.sys_id;// Reject approvalsvar notapproved = new GlideRecord('sysapproval_approver');notapproved.addQuery('source_table', 'sc_req_item');notapproved.addQuery('sysapproval', ritmSysId);notapproved.addQuery('state', 'requested');notapproved.query();while (notapproved.next()) {notapproved.state = 'rejected';notapproved.comments = "Auto-closed after 10 business days. On Hold Reason: " + gr_SRonhold.getDisplayValue('u_on_hold_reason');notapproved.update();}// Close RITMgr_SRonhold.state = '4';gr_SRonhold.comments = "This ticket has been automatically closed due to no activity over the past 10 business days. On Hold Reason: " + gr_SRonhold.getDisplayValue('u_on_hold_reason');gr_SRonhold.update();// Update Requestvar grReq = new GlideRecord('sc_request');grReq.addQuery('sys_id', gr_SRonhold.request);grReq.query();while (grReq.next()) {grReq.state = '4';grReq.update();}// Update Catalog Tasksvar grtask = new GlideRecord('sc_task');grtask.addQuery('request_item', ritmSysId);grtask.query();while (grtask.next()) {grtask.state = '4';grtask.update();}gs.eventQueue('autocancel.requestItem', gr_SRonhold, "", "");ritmCount++;}// ================= LOG =================gs.info("Auto-close completed. Incidents: " + incidentCount + ", RITMs: " + ritmCount);} else {gs.info("Auto-close job skipped (Weekend)");}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-27-2026 12:59 PM
You could basically use flow designer to deliver this requirement.
Please refer to the following video : https://www.youtube.com/watch?v=nYCr1BcUhDI&list=PLzDI891zP4LVUuWhpEFFmNqfMl4KYdjnP&index=5
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-31-2026 12:10 PM - edited 05-31-2026 12:10 PM
Run a Daily scheduled job with following script:
Sample script:
var scheduleSysId = 'YOUR_SCHEDULE_SYS_ID_HERE';
var dc = new DurationCalculator();
dc.setSchedule(scheduleSysId);
var gr = new GlideRecordSecure('task');
gr.addEncodedQuery('sys_class_name=incident^ORsys_class_name=sc_req_item^stateIN-5,3'); // -5 = Pending Approval, 3 = On Hold (Adjust values to match your instance)
gr.query();
while (gr.next()) {
var createdOn = gr.sys_created_on;
var gdtCreated = new GlideDateTime(createdOn);
var gdtNow = new GlideDateTime();
dc.calcDuration(gdtCreated, gdtNow);
var elapsedSeconds = dc.getSeconds();
var elapsedBusinessDays = elapsedSeconds / 86400; // 24 hours converted to seconds
if (elapsedBusinessDays >= 1 && elapsedBusinessDays < 10) {
if (elapsedBusinessDays == 3 || elapsedBusinessDays == 5 || elapsedBusinessDays == 8 ) //e.g remind on days 3, 5, and 8
{
gs.eventQueue('ticket.reminder', gr, gr.sys_id, ''); //Replace your actual notification name
}
}
else if (elapsedBusinessDays >= 10) {
gr.state = 7; // State value for 'Closed'
gr.comments = 'Ticket automatically closed due to inactivity after 10 business days.';
gr.update();
}
}
Regards
Tanushree Maiti
ServiceNow Technical Architect
LinkedIn: https://www.linkedin.com/in/tanushreemaiti