如何向Scheduled Apex类传递参数?——实现指定Case Id的定时关闭需求
这个问题核心要解决两个关键点:给Schedulable类传递Case Id参数,以及高效批量调度(避免单个Case一个任务的资源浪费)。我给你一套完整的实现方案:
1. 改造CloseInactiveCaseSchedulable类,支持接收Case Id列表
Schedulable类的execute方法无法直接接收外部参数,但我们可以通过实例变量+构造器的方式传递数据——Salesforce会序列化调度类的实例并存储,构造器传入的参数会被保留到任务执行时。
public class CloseInactiveCaseSchedulable implements Schedulable { // 存储需要关闭的Case Id列表(私有变量,保证数据安全) private List<Id> caseIdsToClose; // 构造器:接收需要处理的Case Id列表 public CloseInactiveCaseSchedulable(List<Id> caseIds) { this.caseIdsToClose = caseIds; } public void execute(SchedulableContext sc) { // 🔴 重要:执行前再次查询Case,确保状态仍符合条件(防止中途被人工修改) List<Case> casesToUpdate = [ SELECT Id, Status FROM Case WHERE Id IN :caseIdsToClose AND (Status = 'Waiting for customer reply' OR Status = 'Waiting for customer approval') ]; // 设置关闭状态(请根据你的实际业务调整状态值,比如'Closed') for (Case c : casesToUpdate) { c.Status = 'Closed'; } // 批量更新Case if (!casesToUpdate.isEmpty()) { // 使用Database.update的allOrNone=false,允许部分成功(可选,根据业务需求调整) Database.SaveResult[] results = Database.update(casesToUpdate, false); // 记录错误日志(可选,方便排查问题) for (Database.SaveResult res : results) { if (!res.isSuccess()) { for (Database.Error err : res.getErrors()) { System.debug('Failed to update Case ' + res.getId() + ': ' + err.getMessage()); } } } } // 执行完成后删除当前调度任务,避免重复触发(保险操作) System.abortJob(sc.getTriggerId()); } }
2. 优化调度方法,批量创建任务
原来的代码给每个Case单独创建调度,既低效又容易触达平台的调度任务数量上限。我们改成收集所有符合条件的Case Id,只创建一个调度任务:
public static void scheduleCloseCaseJob(List<Case> cases, Map<Id, Case> oldCases) { List<Id> caseIdsToSchedule = new List<Id>(); // 收集需要调度关闭的Case Id for (Case c : cases) { if (c.Status == 'Waiting for customer reply' || c.Status == 'Waiting for customer approval') { caseIdsToSchedule.add(c.Id); } } // 只有当有需要处理的Case时才创建调度任务 if (!caseIdsToSchedule.isEmpty()) { // 计算5天后的执行时间(替换你原来的20天需求) Datetime scheduledTime = Datetime.now().addDays(5); // 生成正确的一次性Cron表达式(避免原来的每月重复执行问题) String cronExpression = String.format( '{0} {1} {2} {3} {4} ? {5}', new List<String>{ String.valueOf(scheduledTime.second()), String.valueOf(scheduledTime.minute()), String.valueOf(scheduledTime.hour()), String.valueOf(scheduledTime.day()), String.valueOf(scheduledTime.month()), String.valueOf(scheduledTime.year()) } ); // 创建唯一的任务名称(避免重名报错) String jobName = 'Close Inactive Cases - ' + Datetime.now().format('yyyyMMddHHmmss'); // 传递Case Id列表给调度类实例,启动任务 System.schedule(jobName, cronExpression, new CloseInactiveCaseSchedulable(caseIdsToSchedule)); } }
关键注意事项
- 权限问题:调度任务的执行用户是创建该任务的用户,确保这个用户拥有Case的修改权限,否则任务执行会失败。
- 时区处理:
Datetime.now()使用的是Salesforce系统时区,如果需要基于特定用户时区计算执行时间,需要先转换时区再计算(比如UserInfo.getTimeZone().convertTime(Datetime.now()))。 - 重复执行防护:我们在
execute方法结尾调用了System.abortJob,同时Cron表达式指定了具体的年、月、日,确保任务只执行一次。 - 错误处理:代码中加入了
Database.update(allOrNone=false)和错误日志打印,方便你排查部分Case更新失败的问题。
内容的提问来源于stack exchange,提问作者mowok1377
相关产品推荐
相关产品推荐

