😊

Salesforceフローで一括処理(Database.Batchable)を呼び出す

2024/07/23に公開

こんにちは。バニッシュ・スタンダードの土屋と申します。今回はSalesforceの話です。

きっかけ

普段使っているフローがコケるようになってしまいました。
「制限を超えました。お客様の組織はこの機能に対する最大限度を超えました。」

トランザクション単位のフローの制限

クエリ総数100件やクエリ取得50000件といったガバナ制限は意識していたのですがSalesforce サーバーの最大CPU時間10,000ミリ秒超えはどうにも対応ができず。
フローが限界に来ているようなのでApexと組み合わせて処理を実行することにしました

処理の流れ

  1. フローからInvocableMethodを呼び出す
  2. InvocableMethodからBatchableを呼び出す

実装

実装は処理の流れとは逆に実装していきます。

一括処理(Database.Batchable)

いわゆる非同期処理です。Database.Batchableインターフェースでstartメソッド,executeメソッド,finishメソッドを実装します。

/**
 * サンプル
 */
public class SampleBatchable implements Database.Batchable<SObject>, Database.Stateful {
    private Integer processCount; // 処理件数

    public SampleBatchable() {
        processCount = 0;
    }

    /**
     * startメソッド
     * Apex の一括処理ジョブの開始時に呼び出されます
     * executeに渡すクエリを生成します
     * 今回のサンプルではすべての取引先を取得しています
     */
    public Database.QueryLocator start(Database.BatchableContext bc) {
        Database.QueryLocator query =Database.getQueryLocator([
            SELECT Id,Name FROM Account
        ]); 
        return query;
    }

    /**
     * executeメソッド
     * メソッドに渡すレコードのバッチごとに呼び出されます。
     */
    public void execute(Database.BatchableContext bc, List<Account> accounts) {

        // 実処理の実装
        for(Account account : accounts) {

            // --------------------------
            // ここに処理を書く
            // --------------------------

            processCount += 1;
        }
    }
  
    /**
     * finishメソッド
     * すべてのバッチが処理された後に呼び出されます
     * 通知や後処理を実装できます
     */
    public void finish(Database.BatchableContext bc) {
        System.Debug('対象件数 = ' + processCount);
    }
}

Batchableを使うときに気をつけること

  • 処理の順番が保証されません
  • 最初のトランザクションが成功し、2番目が失敗した場合、最初のトランザクションで行われたデータベースの更新はロールバックされません。

InvocableMethod

フローから呼び出せるアクションを定義するInvocableMethodアノテーションを使用します

public with sharing class SampleInvocable {

    @InvocableMethod(
        label = 'サンプル' 
        description = 'サンプル説明文'
    )
    public static List<String> execute() {
        List<String> resultMessage = new List<String>();
        try {
            SampleBatchable batchInitial = new SampleBatchable();
            Database.executeBatch(batchInitial, 1);
            resultMessage.add('OK');
        } catch (Exception e) {
            resultMessage.add('ERROR');
            resultMessage.add(e.getTypeName());
            resultMessage.add(e.getMessage());
            resultMessage.add(e.getStackTraceString());
        }
        return resultMessage;
    }
}

フローから呼び出し

処理結果

無事に処理が実行できました

まとめ

コーディングなしで実装できるフローはとても便利なのですがまだ限界があるのでうまくApexと組み合わせていけるといいのかなと思いました。

Discussion