【解決】 Salesforce: UNABLE_TO_LOCK_ROW の解決方法と原因 | Salesforce トラブルシューティング

Salesforceをご利用の皆さん、こんにちは!

突然「UNABLE_TO_LOCK_ROW」というエラーメッセージが表示されて、作業が中断されてしまった経験はありませんか?このエラーは、データの整合性を保つために重要な仕組みですが、予期せず発生すると焦ってしまうものです。ご安心ください。この記事では、このエラーの原因から、Windowsユーザーの皆さんがすぐに試せる解決策、そして将来的に再発を防ぐための恒久的な対策まで、シニアエンジニアのアシスタントである私が詳しく解説します。

結論からお伝えすると、「UNABLE_TO_LOCK_ROW」エラーの多くは一時的な問題であり、**少し時間をおいてからもう一度操作を試す**ことで解決することがほとんどです。

1. Salesforce: UNABLE_TO_LOCK_ROW とは?(概要と緊急度)

「UNABLE_TO_LOCK_ROW」エラーは、Salesforceが特定のレコードを更新しようとした際に、そのレコードが他のユーザーやプロセスによってロックされており、更新できない場合に発生します。

これは、複数のユーザーが同時に同じデータを変更しようとしたときに、データの破損や矛盾を防ぐための重要な安全機構です。いわば、銀行の窓口で同時に複数の人が同じ口座のお金を引き出そうとした場合に、システムが一時的に「この口座は処理中です」と応答するようなものです。

緊急度としては中程度です。ほとんどの場合、一時的な競合によって発生するため、すぐに作業が続行できなくなるわけではありませんが、頻繁に発生すると業務効率が大きく低下する可能性があります。原因を理解し、適切な対策を講じることが重要です。

2. 【最速】今すぐ試すべき解決策

解決策1:手動での再試行と状況確認

最も簡単で効果的な方法は、以下のステップを試すことです。

  1. 少し時間をおいてから再試行する: 多くのロックは数秒から数十秒で解除されます。焦らず、10秒〜1分ほど待ってから、もう一度同じ操作(保存、更新など)を試してみてください。
  2. 他のユーザーに確認する: 同じレコードを現在編集している他のユーザーがいないか、チームメンバーに確認してみましょう。もし編集中のユーザーがいる場合、そのユーザーが保存を完了するか、編集をキャンセルするまで待つ必要があります。
  3. ブラウザのキャッシュをクリアする: まれにブラウザのセッションやキャッシュが原因で問題が発生することもあります。ブラウザのキャッシュをクリアし、Salesforceに再ログインしてから操作を試してみてください。

【補足】バッチ処理などで一括操作中に発生する場合の対策(Windows PowerShellの例)

もしあなたがデータローダーや外部ツールを使ってSalesforceに大量のデータを一括で投入・更新していて、このエラーに頻繁に遭遇する場合、処理に一時的な待機時間を設けることでエラー発生率を下げることができます。以下は、PowerShellスクリプト内で一定時間待機する簡単な例です。

# データ処理ループ内でエラーが発生した場合など、一時的に処理を停止したい場合に利用
# 例: 5秒間待機する
Start-Sleep -Seconds 5

# エラーメッセージをコンソールに出力し、次のレコード処理へ進むなどのロジックと組み合わせる
# Try-Catchブロックと組み合わせて、エラー発生時に待機&再試行ロジックを実装することも可能
# 例: 3回まで再試行する簡易ロジック
$maxRetries = 3
$retryCount = 0
$recordProcessed = $false

while (-not $recordProcessed -and $retryCount -lt $maxRetries) {
    try {
        # ここにSalesforceへのデータ更新処理(例: Salesforce CLIコマンド、API呼び出しなど)を記述
        # 例: sf data update record -s Account -i <RecordId> -v "Name='New Name'"
        
        Write-Host "レコードの更新を試行中..."
        # 実際にはSalesforce CLIやAPI呼び出しを行う部分
        # 仮に成功したと見なす
        $recordProcessed = $true
        Write-Host "レコードが正常に更新されました。"
    }
    catch {
        $errorMessage = $_.Exception.Message
        if ($errorMessage -like "*UNABLE_TO_LOCK_ROW*") {
            $retryCount++
            Write-Warning "UNABLE_TO_LOCK_ROW エラーが発生しました。($retryCount/$maxRetries 回目) 10秒待機して再試行します..."
            Start-Sleep -Seconds 10
        } else {
            Write-Error "予期せぬエラーが発生しました: $($errorMessage)"
            break # UNABLE_TO_LOCK_ROW以外のエラーは再試行せず中断
        }
    }
}

if (-not $recordProcessed) {
    Write-Error "レコードの更新に失敗しました。最大再試行回数に達しました。"
}

このスクリプトは、エラー発生時に自動的に数秒待機し、再試行するロジックの基本的な考え方を示しています。一括処理を自動化している場合に、この考え方を実装することで、手動での介入を減らし、安定性を向上させることができます。

3. Salesforce: UNABLE_TO_LOCK_ROW が発生する主要な原因(複数)

一時的なロック競合は一般的ですが、頻繁に発生する場合は根本的な原因があります。主な原因は以下の通りです。

  • 並行処理(同時編集): 複数のユーザーや自動化プロセス(API連携、バッチ処理など)が、同時に同じレコード、または関連するレコード(例: 親子関係にあるレコード)を更新しようとした場合に発生します。これが最も一般的な原因です。
  • 長いトランザクション: Apexトリガー、フロー、ワークフロールールなどの自動化プロセスが複雑で実行時間が長い場合、その処理中はレコードがロックされた状態が続きます。これにより、他の処理が待機状態となり、ロックエラーが発生しやすくなります。
  • レコードの依存関係: 特定のレコードを更新すると、その親レコードや子レコード、関連するオブジェクトのレコードにもロックがかかることがあります。複雑なリレーションシップを持つオブジェクトでは、予期せぬロック競合が発生することがあります。
  • 外部システムからのAPI連携: 外部のシステムがSalesforce APIを通じて大量のデータを一括で更新しようとした際、ロック競合が発生することがあります。特に、複数のシステムが同じレコード群を同時にターゲットにする場合に顕著です。
  • カスタム開発の不備: Apexコードやフローの設計が最適でない場合、不必要に長い時間レコードをロックしたり、デッドロック(相互にロックを待ち合う状態)を引き起こしたりすることがあります。

4. Salesforceで恒久的に再発を防ぐには

単なる一時的な問題ではなく、頻繁に発生する「UNABLE_TO_LOCK_ROW」エラーは、システム全体のパフォーマンスにも影響を及ぼします。恒久的に再発を防ぐためには、以下の対策を検討してください。

a. トランザクションの最適化と短縮化

  • Apexコードの最適化: トリガーやバッチ処理など、実行時間の長いApexコードを見直し、効率化を図りましょう。SOQLクエリの最適化、ループ処理の改善、DML操作の適切なバッチ処理などが含まれます。
  • フロー(Flow)の簡素化: 複雑なフローは、処理ステップを減らしたり、同期処理から非同期処理(Schedule-Triggered Flowなど)に切り替えたりすることで、レコードロックの時間を短縮できます。
  • バッチ処理のチャンクサイズ調整: 大量のレコードを一括処理する際は、一度に処理するレコード数(チャンクサイズ)を小さく設定することで、個々のトランザクションにかかる時間を短縮し、ロック競合のリスクを低減できます。

b. ロック発生源の特定と監視

  • デバッグログの活用: エラー発生時のデバッグログを確認し、どの処理が、どのレコードに対して、どれくらいの時間ロックを保持していたかを特定します。特に「`ROW_LOCK_EXCEEDED`」のようなメッセージに注目してください。
  • Event Monitoringの活用: SalesforceのEvent Monitoring(アドオン機能)は、システムイベントの詳細なログを提供します。これを利用して、特定のレコードに対する同時アクセス状況やトランザクションのパフォーマンスを詳細に分析し、ロック競合のパターンを特定できます。
  • Salesforce Health Check: 環境の健全性を定期的にチェックし、パフォーマンスボトルネックとなる設定やカスタムコードがないか確認しましょう。

c. データ更新戦略の見直しと自動化の改善

  • 非同期処理の活用: 時間のかかる処理は、@future メソッドやキューアブル Apex、プラットフォームイベントなど、非同期処理に切り替えることを検討しましょう。これにより、ユーザーインタラクション時の即時ロックを回避できます。
  • 再試行ロジックの実装: 外部システムからのAPI呼び出しやデータローダーでの一括更新時には、エラー発生時に自動的に数秒待機し、再試行するロジック(前述のPowerShellの例のような)を組み込むことで、一時的なロックエラーを乗り越えることができます。
  • レコードロック戦略の設計: 複雑なビジネスプロセスにおいて、意図的にレコードをロックする(例: `FOR UPDATE`句を使用)必要がある場合は、そのロック範囲と解除タイミングを慎重に設計し、他の処理への影響を最小限に抑えるようにします。

d. ユーザーへの啓蒙とベストプラクティス

  • 同時編集の回避: ユーザーに対して、重要なレコードや頻繁に更新されるレコードを同時に編集しないよう、ベストプラクティスを共有します。必要に応じて、レコードの状態管理(例: 「編集中」フラグを立てるなど)を導入することも有効です。
  • 作業時間の分散: 大量のデータ更新が必要な業務は、ユーザーが少ない時間帯(例: 業務時間外)に実施するよう計画することで、ロック競合のリスクを低減できます。

「UNABLE_TO_LOCK_ROW」エラーは、Salesforceを利用する上で避けられない側面がありますが、適切な理解と対策を講じることで、その発生を最小限に抑え、快適なSalesforce利用環境を維持することができます。もしこれらの対策を試しても解決しない場合は、Salesforceのサポート窓口へ問い合わせることも検討してください。