Salesforce Apex作业未在触发器中异步运行

Salesforce Apex作业未在触发器中异步运行,salesforce,Salesforce,我在删除前触发器中运行Apex作业,注意到通过Salesforce界面删除单个活动大约需要34秒,删除活动时Apex作业已完成运行。当我使用VisualForce页面在相同数量的记录(15000)上运行相同的Apex作业时,Apex作业将排队,并在VisualForce页面完成后运行 在此屏幕截图中,第一个作业使用VisualForce排队,第二个和第三个作业使用触发器排队: 正如您所看到的,虽然相同数量的记录(15000条)在使用触发器排队时由相同的Apex作业处理,但没有创建和提交批次,完

我在删除前触发器中运行Apex作业,注意到通过Salesforce界面删除单个活动大约需要34秒,删除活动时Apex作业已完成运行。当我使用VisualForce页面在相同数量的记录(15000)上运行相同的Apex作业时,Apex作业将排队,并在VisualForce页面完成后运行

在此屏幕截图中,第一个作业使用VisualForce排队,第二个和第三个作业使用触发器排队:

正如您所看到的,虽然相同数量的记录(15000条)在使用触发器排队时由相同的Apex作业处理,但没有创建和提交批次,完成日期也有很大不同

Apex作业在触发器中排队:

trigger DeleteChilds on Campaign (before delete) {
public static final Integer MAX_DELETED = 500;
Set<ID> ids = new Set<Id>();
List<Parent__c> objs = new List<Parent__c>();   

for(Campaign c : Trigger.old)
    ids.add(c.Id);

objs = [SELECT Id FROM Parent__c WHERE Campaign__c IN :ids];

ids = new Set<Id>();

for(Parent__c s : objs)
    ids.add(s.Id);

Integer childCount = [SELECT count() FROM Childs__c WHERE Parent__c IN :ids];

if(childCount < MAX_DELETED){
    List<Childs__c> childs = [SELECT Id FROM Childs__c WHERE Parent__c IN :ids];

    delete childs;  
} else {                 
    String deleteQuery = 'SELECT Id FROM Childs__c WHERE ';

    for(ID id : ids){
        deleteQuery += String.format(' Parent__c = \'\'{0}\'\' OR', new String[] {id});
    }   

    if(deleteQuery.endsWith('OR')){
        deleteQuery = deleteQuery.substring(0, deleteQuery.length() - 2);
    }               

    BatchDeleteChilds batch = new BatchDeleteChilds();
    batch.deleteQuery = deleteQuery;

    ID batchId = Database.executeBatch(batch);      
}

delete objs;
}
在活动中触发DeleteChilds(删除前){
公共静态最终整数MAX_DELETED=500;
集合ID=新集合();
List objs=new List();
对于(活动c:Trigger.old)
添加(c.Id);
objs=[从父项中选择Id,其中活动位于:Id];
ids=新集合();
用于(父对象:objs)
添加(s.Id);
整数childCount=[从Childs__c中选择count(),其中父项在:id中];
if(已删除的子计数<最大值){
List childs=[从childs_uuuc中选择Id,其中Parent_uuc IN:Id];
删除child;
}否则{
String deleteQuery='从Childs__cwhere'中选择Id';
用于(ID:ids){
deleteQuery+=String.format('Parent\uu c=\'\'\'{0}\'\'或',新字符串[]{id});
}   
if(deleteQuery.endsWith('OR')){
deleteQuery=deleteQuery.substring(0,deleteQuery.length()-2);
}               
BatchDeleteChilds batch=新的BatchDeleteChilds();
batch.deleteQuery=deleteQuery;
ID batchId=数据库.executeBatch(批处理);
}
删除obj;
}
这是Apex的工作:

global class BatchDeleteChilds implements Database.Batchable<sObject> {
public String deleteQuery;

global Database.QueryLocator start(Database.BatchableContext context){
    return Database.getQueryLocator(deleteQuery);
}

global void execute(Database.BatchableContext context, List<sObject> records){
    delete records;
    DataBase.emptyRecycleBin(records);
}   

global void finish(Database.BatchableContext context){

}   
}
全局类BatchDeleteChilds实现数据库。可批处理{
公共字符串查询;
global Database.QueryLocator启动(Database.BatchableContext上下文){
返回Database.getQueryLocator(deleteQuery);
}
全局void execute(Database.BatchableContext上下文,列表记录){
删除记录;
数据库.emptyRecycleBin(记录);
}   
全局void完成(Database.BatchableContext上下文){
}   
}
还有其他人经历过这样的事情吗


谢谢,

你看到的是一种可能永远不会赢的比赛状态。已删除的父对象将在批处理作业执行时提交,这将取消数据库中从子对象到父对象的查找。因此,传递到批处理中的查询将没有记录

  • 预删除子项:(名称='example',父项='123')
  • 后期删除(批处理前)子项:(名称='example',父项\uuu c=null)
我不知道是什么设计决策促使了这种方法,但还有其他选项可用于大规模删除子记录。最简单的方法是将子级到父级的关系设置为主细节。使用这种类型的关系会自动删除子记录


其次,您可以使用visualforce页面覆盖父对象的delete按钮。然后,控制器将对这些子项进行计数,并决定是否启动批处理来删除它们。然后让批处理过程等待删除父对象,直到其完成方法。

有趣的问题。有没有可能在调试登录的情况下运行并共享结果?可能有助于识别可能未作为错误报告给批处理上下文的问题。另外,最好在删除后的上下文中运行它,不是吗?以防活动无法删除。这样就不会丢失子记录。将触发器更改为在删除后运行会导致父对象的活动\uuu\c字段为空,因为该活动已被删除。这不会导致删除,因为[SELECT Id FROM Parent__cwhere Campaign__cin:ids]不会返回任何结果。我决定使用Apex作业的原因是响应接口。虽然从接口中删除父对象将导致删除所有子对象,但页面加载需要35秒才能加载10000个子对象。我明白了,覆盖删除按钮听起来是个不错的选择。如果这对你有效,请告诉我。