+ Start a Discussion
慎吾 木下慎吾 木下 

バッチのInsert処理について

お世話になっております。
オブジェクトに対するInsert処理をバッチで実行しているのですが、
一部のInsertが行われない事象が発生し、どこに原因があるのかがわかりかねるため、
お知恵をお借りしたく投稿しました。

<処理概要>
・SOQLで取得した情報を元に、coupon_History__cオブジェクトにInsert、及びAccountオブジェクトの値をUpdate
・ループ回数は70回程度

<事象>
・AccountオブジェクトのUpdateは全件問題なくできているが、coupon_History__cオブジェクトのInsert処理が出来ない場合がある。
※1000件中200件失敗(エラーログ出力は無し)
※1バッチあたりの処理数を200件に設定しているため、バッチ1回分のInsert処理がスキップされている。
・SOQLで渡されるデータ量は、ループ回数に比例して少なくなる。(例:1ループ目 400件⇒2ループ目 300件・・・・70ループ目 1件)
 
global with sharing class AccumulationCP_Batch implements Database.Batchable<sObject> {

    private String query;
    private String strCPList = AccumulationCP_BatSTClass.strCPList;
    private Integer intPublis = AccumulationCP_BatSTClass.intPublis;

    global AccumulationCP_Batch(String q)
    {
        query = q;
    }

    //バッチ開始処理
    //開始するためにqueryを実行する。この実行されたSOQLのデータ分処理する。
    //5千万件以上のレコードになるとエラーになる。
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator(query);
    }

    //バッチ処理内容
    //scopeにgetQueryLocatorの内容がバッチサイズ分格納されてくる
    global void execute(Database.BatchableContext BC, List<Account> kaiinList)
    {
        List<coupon_History__c> couponHistory = new List<coupon_History__c>();
        
        // 会員情報テーブルの件数分ループ
        // 対象会員数分ループ処理
        for (Integer j = 0 ; j <= kaiinList.size()-1 ; j++) {

            couponHistory.add(new coupon_History__c(coupon_History_mail__c = kaiinList[j].Email__c , 
                                                      coupon__c = strCPList , 
                                                      coupon_issued_point_2__c = kaiinList[j].Accumulation_Point__c , 
                                                      Account__c = kaiinList[j].Id ,
                                                      Notes__c = '' , 
                                                      Issue_status__c = AccumulationCP_BatSTClass.strCP , 
                                                      Issue_date__c = date.today() , 
                                                      Status__c = '未利用' , 
                                                      UsePeriod_From__c = date.today() , 
                                                      UsePeriod_To__c = date.today().AddMonths(+Integer.valueOf(AccumulationCP_BatSTClass.strCouponUseLimit)) , 
                                                      DisplayedShop__c = kaiinList[j].Last_visit_store__c));
            
            kaiinList[j].coupon_issued_point_temp__c = kaiinList[j].Accumulation_Point__c;
            kaiinList[j].Accumulation_PointCP_Flg__c = true;

        }
        
        // クーポン履歴オブジェクトにデータを挿入
        if(couponHistory != null){
            try {
                Database.SaveResult[] sri = Database.insert(couponHistory, false);
                Database.SaveResult[] sru = Database.update(kaiinList, false);
            } catch (DmlException e) {
                System.debug('***** NG : ' + e);
            }
        }

    }

    //バッチ完了処理
    global void finish(Database.BatchableContext BC)
    {
        //完了時の処理
    }
}

上記処理において、kaiinListのUpdateは問題なく行われ、couponHistoryのInsertのみスキップされることが多数あります。
Insert処理とUpdate処理を直近で行うと不具合が発生するなどの情報をお持ちであれば、ご教示ください。
Shingo YamazakiShingo Yamazaki
木下さん

山﨑と申します。

Insert処理とUpdate処理を直近で行うと不具合が発生する、ということは聞いたことがないのですが、
コードを拝見したところ Database.insert() の第二引数を false にしてエラーを無効にしているようなので
たとえば以下のようにログを出力してみて、まずは couponHistory の insert 自体は成功しているのかどうかを確認してみてはいかがでしょうか。

参考:https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_database_saveresult.htm
 
try {
    Database.SaveResult[] sri = Database.insert(couponHistory, false);
    Database.SaveResult[] sru = Database.update(kaiinList, false);

    for (Database.SaveResult sr : sri) {
        if (sr.isSuccess()) {
            // Operation was successful, so get the ID of the record that was processed
            System.debug('Successfully inserted Coupon_History. ID: ' + sr.getId());
        }
        else {
            // Operation failed, so get all errors                
            for(Database.Error err : sr.getErrors()) {
                System.debug('The following error has occurred.');                    
                System.debug(err.getStatusCode() + ': ' + err.getMessage());
                System.debug('Coupon_History fields that affected this error: ' + err.getFields());
            }
        }
    }
                                                                       
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}

(あるいは、単純にエラーを捕捉しないで確認してもいいかもしれません)

 
慎吾 木下慎吾 木下
山﨑さん

ご返信有難うございます。
いまだ解決しておらず、アドバイス大変助かりました。

さっそくご教示頂いたように、Insertログを出力するよう修正します。

なお、当処理ですが、毎週月曜に実行されるものであり、
且つ件数が多い場合のみInsertされない事象が発生するため、
本番環境での処理実行を待った後に、改めて再度ご報告させて頂きます。
 
Shingo YamazakiShingo Yamazaki
木下さん

情報を補足していただきありがとうございます。
データ量が多い場合のみ発生する、ということは
なんらかのガバナ制限が関係しているかもしれませんね。。。
いずれにせよ、エラーログから何かわかるかもしれません。

よろしくお願いします。