Skip to content

Instantly share code, notes, and snippets.

@aidan-harding
Last active January 12, 2022 10:30
Show Gist options
  • Save aidan-harding/b19d230e9ee4b4df5046c27b33f6f3dc to your computer and use it in GitHub Desktop.
Save aidan-harding/b19d230e9ee4b4df5046c27b33f6f3dc to your computer and use it in GitHub Desktop.
Salesforce locks for deleting?

I have a scenario where an external system is calling Salesforce API, causing a trigger to run. That trigger needs to delete EmailMessage records where the RelatedTo field is an Account.

We're getting UNABLE_TO_LOCK_ROW errors when the external system's API calls overlap and the trigger attempts to delete multiple emails on the same Account at the same time.

This is totally understandable based on how record-locking works. RelatedTo is either a required lookup or a Master-Detail so deleting the EmailMessage would require a lock on the related Account.

I tried to solve the problem by adding FOR UPDATE to the query in the trigger where it fetches the EmailMessage records.

But, we still observe UNABLE_TO_LOCK_ROW as a DmlException (if it were a QueryException, then that might be due to the 10-second limit timing out).

Looking again at the locking documents (and reading the actual words FOR UPDATE), it says that a query with FOR UPDATE "Locks all records retrieved in SELECT statement that uses FOR UPDATE."

So, if I lock the EmailMessage, I should not expect it to lock the related Account. I'm locking as if I want to update the record. When I delete the EmailMessage, it tries to lock the Account and fails.

So, what I'd really need is a SOQL clause like FOR DELETE. Or I'd need to do an extra SOQL on the RelatedToIds to explicitly lock the Accounts.

So locking FOR UPDATE kind-of locks the record as if you want to update it. But it doesn't appear to take into account something like Roll-Up summaries. So you could lock a record with a Roll-Up summary FOR UPDATE and still get an UNABLE_TO_LOCK_ROW error if you attempt to update it. And it's certainly not strong enough if you plan to delete the record.

Fun, and nearly impossible to test!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment