7

I have an app that uses the restforce gem to make queries against Salesforce. I ran into an issue with locked rows (UNABLE_TO_LOCK_ROW error), so now I would like to select Contacts, Leads, Opportunities, and Tasks with the FOR UPDATE clause, but I keep getting this error:

Faraday::ClientError: MALFORMED_QUERY: FOR UPDATE not allowed in this context

None of these queries work:

  1. client.query("SELECT Id, Description from Task FOR UPDATE")
  2. client.query("SELECT Id, Description from Task LIMIT 2 FOR UPDATE")
  3. client.query("SELECT Id, Description from Lead FOR UPDATE")
  4. client.query("SELECT Id, Description from Lead LIMIT 2 FOR UPDATE")

They all throw the error MALFORMED_QUERY. How the heck am I supposed to use FOR UPDATE?

If I can't use FOR UPDATE with the REST API, how do I tell Salesforce I need to lock a row and prevent the UNABLE_TO_LOCK_ROW error?

Any ideas would be helpful! Thanks!

2 Answers 2

7

You can really only effectively use FOR UPDATE for record locking within Apex code (which you could expose via a REST resource and call from your external system). It will lock the records returned by the query for the remainder of the transaction, and the transaction is free to make updates to the records in question while it holds the lock. Other simultaneous transactions that attempt to lock the record will have to wait.

You'll be unable to use FOR UPDATE when simply querying a record via the standard REST API because the transaction is over as soon as the data is returned to you. If you're then making an update to the record via the standard REST API after the initial query, this is a separate transaction and Salesforce does not allow any mechanism to lock records between transactions like this. In order to avoid the misconception that a record is locked after your query transaction takes place, Salesforce returns the error messages you've been getting.

2
  • Would it be appropriate to retry the REST call later with progressive backoff (e.g. 10 seconds later, then 10 minutes, then 1 hour, etc.) until I stop getting the UNABLE_TO_LOCK_ROW error?
    – boo-urns
    Commented Jan 18, 2016 at 6:07
  • I think it would really depend on your use case. If it was a critical record update, it may make sense to retry immediately or after only a few seconds. As an alternative (and depending on how comfortable you are with Apex), you could expose and call a custom Apex REST resource, which could then query the records you're interested in using FOR UPDATE, run some business logic according to the parameters you provided, update the records, and return results for your external system in its response.
    – JCD
    Commented Jan 18, 2016 at 22:36
0

Record locking works with the REST API the same as it does with any other interface to salesforce.com. It's true that it's possible for a REST API call to overwrite another's changes during a query -> do something -> update cycle, but if two edits reach the database at the same time, one of them will get the usual UNABLE_TO_OBTAIN_ROW_LOCK error. This is easily noticeable when there are long transactions that occur on the record so you can test it (for example, creating a trigger that locks up the transaction for 7-8 seconds, you can launch a second update that will fail). The UI also respects row locking, and will notify a user when a change has been made to a record while they were working on it in order to avoid overwriting the data.

1
  • So is my query wrong? Why am I getting an error saying that I can't use FOR UPDATE?
    – boo-urns
    Commented Jan 16, 2016 at 21:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .