scheduled-jobs
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseScheduled Jobs for ServiceNow
ServiceNow 定时任务
Scheduled Jobs automate recurring tasks, batch processing, and maintenance operations.
定时任务可实现周期性任务、批处理和维护操作的自动化。
Job Types
任务类型
| Type | Table | Purpose |
|---|---|---|
| Scheduled Script Execution | sysauto_script | Run custom scripts |
| Report Scheduler | sysauto_report | Generate and email reports |
| Table Cleaner | sys_auto_flush | Delete old records |
| LDAP Refresh | ldap_server_config | Sync LDAP data |
| Discovery | discovery_schedule | Network discovery |
| 类型 | 表名 | 用途 |
|---|---|---|
| 定时脚本执行 | sysauto_script | 运行自定义脚本 |
| 报表调度器 | sysauto_report | 生成并发送报表邮件 |
| 表清理器 | sys_auto_flush | 删除旧记录 |
| LDAP刷新 | ldap_server_config | 同步LDAP数据 |
| 发现任务 | discovery_schedule | 网络发现 |
Scheduled Script Execution (ES5)
定时脚本执行(ES5)
Basic Scheduled Job
基础定时任务
javascript
// Table: sysauto_script
// Name: Close Stale Incidents
// Run: Daily at 2:00 AM
// Script (ES5 ONLY!):
(function executeScheduledJob() {
var LOG_PREFIX = '[CloseStaleIncidents] ';
var closedCount = 0;
// Find incidents inactive for 30 days
var staleDate = new GlideDateTime();
staleDate.addDaysLocalTime(-30);
var gr = new GlideRecord('incident');
gr.addQuery('state', 'IN', '1,2,3'); // New, In Progress, On Hold
gr.addQuery('sys_updated_on', '<', staleDate);
gr.addQuery('active', true);
gr.query();
gs.info(LOG_PREFIX + 'Found ' + gr.getRowCount() + ' stale incidents');
while (gr.next()) {
gr.state = 7; // Closed
gr.close_code = 'Closed/Resolved by Caller';
gr.close_notes = 'Auto-closed due to 30 days of inactivity';
gr.update();
closedCount++;
}
gs.info(LOG_PREFIX + 'Closed ' + closedCount + ' stale incidents');
})();javascript
// Table: sysauto_script
// Name: Close Stale Incidents
// Run: Daily at 2:00 AM
// Script (ES5 ONLY!):
(function executeScheduledJob() {
var LOG_PREFIX = '[CloseStaleIncidents] ';
var closedCount = 0;
// Find incidents inactive for 30 days
var staleDate = new GlideDateTime();
staleDate.addDaysLocalTime(-30);
var gr = new GlideRecord('incident');
gr.addQuery('state', 'IN', '1,2,3'); // New, In Progress, On Hold
gr.addQuery('sys_updated_on', '<', staleDate);
gr.addQuery('active', true);
gr.query();
gs.info(LOG_PREFIX + 'Found ' + gr.getRowCount() + ' stale incidents');
while (gr.next()) {
gr.state = 7; // Closed
gr.close_code = 'Closed/Resolved by Caller';
gr.close_notes = 'Auto-closed due to 30 days of inactivity';
gr.update();
closedCount++;
}
gs.info(LOG_PREFIX + 'Closed ' + closedCount + ' stale incidents');
})();Scheduled Job with Error Handling (ES5)
带错误处理的定时任务(ES5)
javascript
// Name: Sync User Data
// Run: Every 6 hours
(function executeScheduledJob() {
var LOG_PREFIX = '[SyncUserData] ';
var stats = {
processed: 0,
updated: 0,
errors: 0
};
try {
// Get users needing sync
var gr = new GlideRecord('sys_user');
gr.addQuery('u_needs_sync', true);
gr.addQuery('active', true);
gr.setLimit(1000); // Process in batches
gr.query();
while (gr.next()) {
stats.processed++;
try {
var updated = syncUserFromSource(gr);
if (updated) {
stats.updated++;
}
} catch (e) {
stats.errors++;
gs.error(LOG_PREFIX + 'Error syncing user ' + gr.user_name + ': ' + e.message);
}
}
gs.info(LOG_PREFIX + 'Sync complete: ' + JSON.stringify(stats));
// Send summary email if errors
if (stats.errors > 0) {
sendErrorSummary(stats);
}
} catch (e) {
gs.error(LOG_PREFIX + 'Job failed: ' + e.message);
notifyAdmins('User sync job failed: ' + e.message);
}
function syncUserFromSource(userGr) {
// Sync logic here
userGr.u_needs_sync = false;
userGr.u_last_sync = new GlideDateTime();
return userGr.update();
}
function sendErrorSummary(stats) {
gs.eventQueue('user.sync.errors', null, JSON.stringify(stats), '');
}
function notifyAdmins(message) {
gs.eventQueue('system.job.failure', null, message, '');
}
})();javascript
// Name: Sync User Data
// Run: Every 6 hours
(function executeScheduledJob() {
var LOG_PREFIX = '[SyncUserData] ';
var stats = {
processed: 0,
updated: 0,
errors: 0
};
try {
// Get users needing sync
var gr = new GlideRecord('sys_user');
gr.addQuery('u_needs_sync', true);
gr.addQuery('active', true);
gr.setLimit(1000); // Process in batches
gr.query();
while (gr.next()) {
stats.processed++;
try {
var updated = syncUserFromSource(gr);
if (updated) {
stats.updated++;
}
} catch (e) {
stats.errors++;
gs.error(LOG_PREFIX + 'Error syncing user ' + gr.user_name + ': ' + e.message);
}
}
gs.info(LOG_PREFIX + 'Sync complete: ' + JSON.stringify(stats));
// Send summary email if errors
if (stats.errors > 0) {
sendErrorSummary(stats);
}
} catch (e) {
gs.error(LOG_PREFIX + 'Job failed: ' + e.message);
notifyAdmins('User sync job failed: ' + e.message);
}
function syncUserFromSource(userGr) {
// Sync logic here
userGr.u_needs_sync = false;
userGr.u_last_sync = new GlideDateTime();
return userGr.update();
}
function sendErrorSummary(stats) {
gs.eventQueue('user.sync.errors', null, JSON.stringify(stats), '');
}
function notifyAdmins(message) {
gs.eventQueue('system.job.failure', null, message, '');
}
})();Batch Processing Job (ES5)
批处理任务(ES5)
javascript
// Name: Process Large Dataset
// Run: Weekly on Sunday at 1:00 AM
(function executeScheduledJob() {
var LOG_PREFIX = '[BatchProcessor] ';
var BATCH_SIZE = 500;
var MAX_RUNTIME = 3600000; // 1 hour in ms
var startTime = new Date().getTime();
var processed = 0;
var hasMore = true;
while (hasMore && !isTimeExceeded()) {
hasMore = processBatch();
}
if (hasMore) {
gs.warn(LOG_PREFIX + 'Job stopped due to time limit. Processed: ' + processed);
// Re-queue for next run
queueContinuation();
} else {
gs.info(LOG_PREFIX + 'Job complete. Total processed: ' + processed);
}
function processBatch() {
var gr = new GlideRecord('u_large_table');
gr.addQuery('u_processed', false);
gr.setLimit(BATCH_SIZE);
gr.query();
if (!gr.hasNext()) {
return false;
}
while (gr.next()) {
processRecord(gr);
processed++;
}
return true;
}
function processRecord(gr) {
// Processing logic
gr.u_processed = true;
gr.u_processed_date = new GlideDateTime();
gr.update();
}
function isTimeExceeded() {
var elapsed = new Date().getTime() - startTime;
return elapsed > MAX_RUNTIME;
}
function queueContinuation() {
// Queue another run
var job = new GlideRecord('sysauto_script');
if (job.get('name', 'Process Large Dataset - Continuation')) {
job.next_action = new GlideDateTime();
job.update();
}
}
})();javascript
// Name: Process Large Dataset
// Run: Weekly on Sunday at 1:00 AM
(function executeScheduledJob() {
var LOG_PREFIX = '[BatchProcessor] ';
var BATCH_SIZE = 500;
var MAX_RUNTIME = 3600000; // 1 hour in ms
var startTime = new Date().getTime();
var processed = 0;
var hasMore = true;
while (hasMore && !isTimeExceeded()) {
hasMore = processBatch();
}
if (hasMore) {
gs.warn(LOG_PREFIX + 'Job stopped due to time limit. Processed: ' + processed);
// Re-queue for next run
queueContinuation();
} else {
gs.info(LOG_PREFIX + 'Job complete. Total processed: ' + processed);
}
function processBatch() {
var gr = new GlideRecord('u_large_table');
gr.addQuery('u_processed', false);
gr.setLimit(BATCH_SIZE);
gr.query();
if (!gr.hasNext()) {
return false;
}
while (gr.next()) {
processRecord(gr);
processed++;
}
return true;
}
function processRecord(gr) {
// Processing logic
gr.u_processed = true;
gr.u_processed_date = new GlideDateTime();
gr.update();
}
function isTimeExceeded() {
var elapsed = new Date().getTime() - startTime;
return elapsed > MAX_RUNTIME;
}
function queueContinuation() {
// Queue another run
var job = new GlideRecord('sysauto_script');
if (job.get('name', 'Process Large Dataset - Continuation')) {
job.next_action = new GlideDateTime();
job.update();
}
}
})();Schedule Configuration
调度配置
Run Frequencies
运行频率
| Frequency | Cron | Example |
|---|---|---|
| Every 5 minutes | | Health checks |
| Hourly | | Data sync |
| Daily at midnight | | Cleanup |
| Weekly Sunday | | Reports |
| Monthly 1st | | Billing |
| Custom | Various | Specific needs |
| 频率 | Cron表达式 | 示例 |
|---|---|---|
| 每5分钟一次 | | 健康检查 |
| 每小时一次 | | 数据同步 |
| 每日午夜 | | 清理操作 |
| 每周日 | | 报表生成 |
| 每月1号 | | 账单处理 |
| 自定义 | 多种表达式 | 特定需求 |
Create Scheduled Job (ES5)
创建定时任务(ES5)
javascript
// Create scheduled job programmatically (ES5 ONLY!)
var job = new GlideRecord('sysauto_script');
job.initialize();
job.setValue('name', 'Nightly Cleanup');
job.setValue('active', true);
// Schedule: Daily at 2:00 AM
job.setValue('run_type', 'daily');
job.setValue('run_time', '02:00:00');
// Or use explicit schedule
job.setValue('run_dayofweek', 'daily');
// Script
job.setValue('script',
'(function executeScheduledJob() {\n' +
' var gr = new GlideRecord("sys_audit_delete");\n' +
' gr.addQuery("sys_created_on", "<", gs.daysAgo(90));\n' +
' gr.deleteMultiple();\n' +
' gs.info("Cleanup complete");\n' +
'})();'
);
// Run as system
job.setValue('run_as', ''); // Empty = System
job.insert();javascript
// Create scheduled job programmatically (ES5 ONLY!)
var job = new GlideRecord('sysauto_script');
job.initialize();
job.setValue('name', 'Nightly Cleanup');
job.setValue('active', true);
// Schedule: Daily at 2:00 AM
job.setValue('run_type', 'daily');
job.setValue('run_time', '02:00:00');
// Or use explicit schedule
job.setValue('run_dayofweek', 'daily');
// Script
job.setValue('script',
'(function executeScheduledJob() {\n' +
' var gr = new GlideRecord("sys_audit_delete");\n' +
' gr.addQuery("sys_created_on", "<", gs.daysAgo(90));\n' +
' gr.deleteMultiple();\n' +
' gs.info("Cleanup complete");\n' +
'})();'
);
// Run as system
job.setValue('run_as', ''); // Empty = System
job.insert();Conditional Execution
条件执行
javascript
// Job that checks conditions before running (ES5 ONLY!)
(function executeScheduledJob() {
var LOG_PREFIX = '[ConditionalJob] ';
// Check if job should run
if (!shouldRun()) {
gs.info(LOG_PREFIX + 'Skipping execution - conditions not met');
return;
}
// Execute main logic
executeMainTask();
function shouldRun() {
// Check business hours
var now = new GlideDateTime();
var hour = parseInt(now.getLocalTime().getByFormat('HH'), 10);
// Only run outside business hours (before 6am or after 8pm)
if (hour >= 6 && hour < 20) {
return false;
}
// Check for active change freeze
var freeze = new GlideRecord('change_request');
freeze.addQuery('type', 'freeze');
freeze.addQuery('state', 'implement');
freeze.query();
if (freeze.hasNext()) {
gs.info(LOG_PREFIX + 'Change freeze active');
return false;
}
return true;
}
function executeMainTask() {
// Main job logic here
gs.info(LOG_PREFIX + 'Executing main task');
}
})();javascript
// Job that checks conditions before running (ES5 ONLY!)
(function executeScheduledJob() {
var LOG_PREFIX = '[ConditionalJob] ';
// Check if job should run
if (!shouldRun()) {
gs.info(LOG_PREFIX + 'Skipping execution - conditions not met');
return;
}
// Execute main logic
executeMainTask();
function shouldRun() {
// Check business hours
var now = new GlideDateTime();
var hour = parseInt(now.getLocalTime().getByFormat('HH'), 10);
// Only run outside business hours (before 6am or after 8pm)
if (hour >= 6 && hour < 20) {
return false;
}
// Check for active change freeze
var freeze = new GlideRecord('change_request');
freeze.addQuery('type', 'freeze');
freeze.addQuery('state', 'implement');
freeze.query();
if (freeze.hasNext()) {
gs.info(LOG_PREFIX + 'Change freeze active');
return false;
}
return true;
}
function executeMainTask() {
// Main job logic here
gs.info(LOG_PREFIX + 'Executing main task');
}
})();Job Monitoring
任务监控
Check Job Status (ES5)
检查任务状态(ES5)
javascript
// Query scheduled job history (ES5 ONLY!)
var history = new GlideRecord('sys_trigger');
history.addQuery('name', 'CONTAINS', 'Nightly Cleanup');
history.orderByDesc('sys_created_on');
history.setLimit(10);
history.query();
while (history.next()) {
gs.info('Job: ' + history.getValue('name') +
' | State: ' + history.getValue('state') +
' | Next: ' + history.getValue('next_action'));
}javascript
// Query scheduled job history (ES5 ONLY!)
var history = new GlideRecord('sys_trigger');
history.addQuery('name', 'CONTAINS', 'Nightly Cleanup');
history.orderByDesc('sys_created_on');
history.setLimit(10);
history.query();
while (history.next()) {
gs.info('Job: ' + history.getValue('name') +
' | State: ' + history.getValue('state') +
' | Next: ' + history.getValue('next_action'));
}Job with Metrics (ES5)
带指标统计的任务(ES5)
javascript
// Job that records performance metrics (ES5 ONLY!)
(function executeScheduledJob() {
var LOG_PREFIX = '[MetricsJob] ';
var startTime = new Date().getTime();
var metrics = {
startTime: new GlideDateTime().getDisplayValue(),
recordsProcessed: 0,
errors: 0
};
try {
// Main processing
var gr = new GlideRecord('incident');
gr.addQuery('active', true);
gr.query();
while (gr.next()) {
processRecord(gr);
metrics.recordsProcessed++;
}
} catch (e) {
metrics.errors++;
gs.error(LOG_PREFIX + 'Error: ' + e.message);
} finally {
// Record metrics
metrics.endTime = new GlideDateTime().getDisplayValue();
metrics.duration = (new Date().getTime() - startTime) / 1000;
recordMetrics(metrics);
}
function processRecord(gr) {
// Processing logic
}
function recordMetrics(metrics) {
var metricsRecord = new GlideRecord('u_job_metrics');
metricsRecord.initialize();
metricsRecord.setValue('u_job_name', 'MetricsJob');
metricsRecord.setValue('u_start_time', metrics.startTime);
metricsRecord.setValue('u_end_time', metrics.endTime);
metricsRecord.setValue('u_duration', metrics.duration);
metricsRecord.setValue('u_records_processed', metrics.recordsProcessed);
metricsRecord.setValue('u_errors', metrics.errors);
metricsRecord.insert();
gs.info(LOG_PREFIX + 'Metrics: ' + JSON.stringify(metrics));
}
})();javascript
// Job that records performance metrics (ES5 ONLY!)
(function executeScheduledJob() {
var LOG_PREFIX = '[MetricsJob] ';
var startTime = new Date().getTime();
var metrics = {
startTime: new GlideDateTime().getDisplayValue(),
recordsProcessed: 0,
errors: 0
};
try {
// Main processing
var gr = new GlideRecord('incident');
gr.addQuery('active', true);
gr.query();
while (gr.next()) {
processRecord(gr);
metrics.recordsProcessed++;
}
} catch (e) {
metrics.errors++;
gs.error(LOG_PREFIX + 'Error: ' + e.message);
} finally {
// Record metrics
metrics.endTime = new GlideDateTime().getDisplayValue();
metrics.duration = (new Date().getTime() - startTime) / 1000;
recordMetrics(metrics);
}
function processRecord(gr) {
// Processing logic
}
function recordMetrics(metrics) {
var metricsRecord = new GlideRecord('u_job_metrics');
metricsRecord.initialize();
metricsRecord.setValue('u_job_name', 'MetricsJob');
metricsRecord.setValue('u_start_time', metrics.startTime);
metricsRecord.setValue('u_end_time', metrics.endTime);
metricsRecord.setValue('u_duration', metrics.duration);
metricsRecord.setValue('u_records_processed', metrics.recordsProcessed);
metricsRecord.setValue('u_errors', metrics.errors);
metricsRecord.insert();
gs.info(LOG_PREFIX + 'Metrics: ' + JSON.stringify(metrics));
}
})();MCP Tool Integration
MCP工具集成
Available Tools
可用工具
| Tool | Purpose |
|---|---|
| Create scheduled job |
| Find existing jobs |
| Test job script |
| Check job execution logs |
| 工具 | 用途 |
|---|---|
| 创建定时任务 |
| 查找现有任务 |
| 测试任务脚本 |
| 查看任务执行日志 |
Example Workflow
示例工作流
javascript
// 1. Create scheduled job
await snow_schedule_job({
name: 'Daily Report Generator',
run_type: 'daily',
run_time: '06:00:00',
script: '/* report generation script */',
active: true
});
// 2. Test the script
await snow_execute_script_with_output({
script: '/* test job script */'
});
// 3. Check logs
await snow_get_logs({
filter: 'message CONTAINS "Daily Report"',
limit: 50
});javascript
// 1. Create scheduled job
await snow_schedule_job({
name: 'Daily Report Generator',
run_type: 'daily',
run_time: '06:00:00',
script: '/* report generation script */',
active: true
});
// 2. Test the script
await snow_execute_script_with_output({
script: '/* test job script */'
});
// 3. Check logs
await snow_get_logs({
filter: 'message CONTAINS "Daily Report"',
limit: 50
});Best Practices
最佳实践
- Logging - Comprehensive logging for debugging
- Error Handling - Try-catch with notifications
- Batching - Process large datasets in batches
- Time Limits - Check runtime to prevent timeouts
- Off-Peak - Schedule during low-usage periods
- Idempotent - Safe to run multiple times
- Monitoring - Record metrics and status
- ES5 Only - No modern JavaScript syntax
- 日志记录 - 完善的日志便于调试
- 错误处理 - 使用Try-Catch并配置通知
- 批处理 - 分批次处理大型数据集
- 时间限制 - 检查运行时长以避免超时
- 非高峰时段 - 在低负载时段调度任务
- 幂等性 - 可安全重复执行
- 监控 - 记录指标和状态
- 仅支持ES5 - 不使用现代JavaScript语法