1

My custom code is executed using a queuable class. Sometime it runs perfectly, other times it gives this error:

Failed to update list. Error: System.DmlException: Update failed. First exception on row 0 with id a0fW0000000kws9IAA; first error: UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record or 1 records: 003W000000VefbrIAB

I noticed this only happens when a specific future job completes approximately ten seconds later than my queuable job. However, occasionally the future job finishes quickly, about the same time my queuable job completes. In this case, my code runs perfectly.

My intuition is this, the future job has locked the record my queuable job is trying to update and, if the future job takes a long time to execute, my queuable job times out before it can gain access to the record.

Is this future job the cause of the issue? If so, what possibilities are there to remedy this?

3

This sort of situation is exactly what the FOR UPDATE clause is for:

Locking Statements

In Apex, you can use FOR UPDATE to lock sObject records while they’re being updated in order to prevent race conditions and other thread safety problems. While an sObject record is locked, no other client or user is allowed to make updates either through code or the Salesforce user interface. The client locking the records can perform logic on the records and make updates with the guarantee that the locked records won’t be changed by another client during the lock period. The lock gets released when the transaction completes.

To lock a set of sObject records in Apex, embed the keywords FOR UPDATE after any inline SOQL statement. For example, the following statement, in addition to querying for two accounts, also locks the accounts that are returned:

Account [] accts = [SELECT Id FROM Account LIMIT 2 FOR UPDATE];

Note You can’t use the ORDER BY keywords in any SOQL query that uses locking.

Locking Considerations

  • While the records are locked by a client, the locking client can modify their field values in the database in the same transaction. Other clients have to wait until the transaction completes and the records are no longer locked before being able to update the same records. Other clients can still query the same records while they’re locked.
  • If you attempt to lock a record currently locked by another client, your process waits for the lock to be released before acquiring a new lock. If the lock isn’t released within 10 seconds, you will get a QueryException. Similarly, if you attempt to update a record currently locked by another client and the lock isn’t released within 10 seconds, you will get a DmlException.
  • If a client attempts to modify a locked record, the update operation might succeed if the lock gets released within a short amount of time after the update call was made. In this case, it is possible that the updates will overwrite those made by the locking client if the second client obtained an old copy of the record. To prevent this from happening, the second client must lock the record first. The locking process returns a fresh copy of the record from the database through the SELECT statement. The second client can use this copy to make new updates.
  • When you perform a DML operation on one record, related records are locked in addition to the record in question. For more information, see the Record Locking Cheat Sheet.

Use care when setting locks in your Apex code. See Avoiding Deadlocks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.