どんな取り組みか
Salesforceのカスタムオブジェクトへのデータ一括登録機能において、「30件以上を登録するとエラーが発生する」という問題が発生しました。これはApexのSystem.LimitException、つまりガバナ制限によるものです。当初は単純な実装ミスと思われましたが、調査と修正の過程で3種類のガバナ制限が連鎖的に発生していることが判明しました。
この機能では、登録対象レコードの確定に外部オブジェクトを複数参照する必要があり、ネットワーク越しの問い合わせが発生します。ユーザーエクスペリエンスの低下を防ぐため、外部オブジェクトの参照処理はQueueableで非同期化する設計が採用されていました。この非同期処理の構成が、連鎖的なガバナ制限の要因となっていました。
オブジェクトAは入力データの重複チェックに用いられ、一括保存後にそのIDを元にQueueableでオブジェクトBを生成する流れでした。
使われた技術スタック
- Salesforce Apex
- SOQL
- Queueableインターフェース
- カスタムオブジェクト
- 外部オブジェクト
- レコードトリガーフロー
実装のポイント
以下の3種類のガバナ制限が特定され、それぞれ対策が講じられました。
Act 1: 同期SOQL数の制限
問題: エラーログは「System.LimitException: Too many SOQL queries」を示しました。実装ではfor文内に3つのSOQLがあり、件数に比例してSOQL数が増加し、制限を超過していました。
対策: SOQLをfor文の外に出し、必要なデータを事前に一括取得してMapに格納する方法に変更しました。これにより、件数に関わらずSOQLは3回で済むようになり、制限をクリアしました。
// 事前に一括取得
Map<String, ObjectA__c> recordMap = new Map<String, ObjectA__c>();
for (ObjectA__c r : [SELECT Id, Code__c FROM ObjectA__c WHERE Code__c IN :codes]) {
recordMap.put(r.Code__c, r);
}
// キュー・重複チェックも同様に事前取得 ...
for (InputRecord input : inputs) {
ObjectA__c record = recordMap.get(input.code);
// Map 参照は SOQL にカウントされない
// ...
}
Act 2: enqueueJob数の制限
問題: 次に「System.LimitException: Too many queueable jobs added to the queue」が発生しました。オブジェクトA登録後に起動するフロー内のApexで、レコードトリガーフローが複数レコードを1回の実行にまとめるため、制限を超過していました。
対策: 1レコードずつキューに積むのをやめ、複数レコードをまとめて処理するチャンク方式に変更しました。制限内に収まるようになりました。
@InvocableMethod(...)
public static void createRelatedRecords(List<Id> recordIds) {
Integer chunkSize = 50;
for (Integer i = 0; i < recordIds.size(); i += chunkSize) {
Integer end = Math.min(i + chunkSize, recordIds.size());
List<Id> chunk = new List<Id>(recordIds.subList(i, end));
System.enqueueJob(new ObjectBCreationJob(chunk));
}
}
Act 3: 非同期SOQL数の制限
問題: 最後に「System.LimitException: Too many SOQL queries」が発生しました。Queueable内のSOQL制限です。ObjectBCreationJobでは1レコードあたり12個のSOQLが発行されており、チャンクサイズによって制限を超過していました。
対策: 非同期SOQL制限とenqueueJob制限の両方を満たすよう、チャンクサイズを調整しました。これにより、制限をクリアしました。
得られた成果や学び
今回の実装で対処したガバナ制限は、同期SOQL、enqueueJob、非同期SOQLの3点です。それぞれ、SOQLの事前一括取得、チャンク単位でのジョブ起動、チャンクサイズの調整によって解決されました。
最大件数が多くなった場合、チャンク処理だけでは対応が難しくなる可能性も考えられます。外部オブジェクトをビューにまとめる、あるいは別の非同期処理パターンを検討する必要があるかもしれません。
この経験から、ガバナ制限を設計段階から意識することの重要性が再確認されました。特に外部オブジェクトを参照する処理を組み込む場合、1トランザクションのSOQL数、キューに積むジョブ数、1ジョブあたりのSOQL数は事前に見積もっておくことで、本番環境での予期せぬエラーを回避できます。
まとめ
Salesforce環境でApexの一括登録処理が外部オブジェクトを参照する際、複数のガバナ制限に直面する可能性があります。本記事では、同期SOQL、Queueableジョブ、非同期SOQLの各制限に対し、SOQLのバルク化、チャンク処理によるジョブ起動、適切なチャンクサイズの調整といった具体的な対策を講じた事例を紹介しました。これらの対策は、Salesforceのガバナ制限を考慮した堅牢なシステム設計において不可欠です。実装者は、設計段階からガバナ制限を意識し、処理量に応じた最適な非同期処理パターンを選択することが求められます。
出典: https://qiita.com/vayaci/items/bc89ccd4593a9ee42e44
Related Certifications
この記事に関連する技術領域の認定資格
Salesforce 関連資格
- Salesforce Certified Administrator
- Salesforce Certified Platform Developer I
- Salesforce Certified Platform Developer II
- Salesforce Certified Application Architect
- Salesforce Certified System Architect
- Salesforce Certified Technical Architect
AWS 関連資格
- AWS Certified Cloud Practitioner
- AWS Certified Solutions Architect – Associate
- AWS Certified Developer – Associate
- AWS Certified Solutions Architect – Professional
- AWS Certified DevOps Engineer – Professional
- AWS Certified Machine Learning – Specialty
※ 認定資格は技術スキルの体系的な学習に役立ちます。試験の出題範囲や受験要件は変更される場合があるため、受験前に必ず公式サイトで最新情報をご確認ください。
SF Tech & Win
Salesforce × AWS × AI 連携の実装ノウハウ
SIer・スタートアップ・中小企業のDX推進に役立つアーキテクチャ事例・実装パターン・最新アップデート情報を毎朝配信。


コメント