5

The documentation says:

The lock gets released when the transaction completes.

However I can validate that it also gets released when a callout is made!

Here a two test methods:

public static void testWithoutCallout(final Id leadId)
{
    System.debug(DateTime.now().format('m:s') + ': Lock requested');
    final Lead lead = [Select id From Lead where id = :leadId FOR UPDATe];
    System.debug(DateTime.now().format('m:s') + ': Lock acquired');
    for(Integer i = 0; i < 30000000; i++) {} 
    System.debug(DateTime.now().format('m:s') + ': Done');
}

public static void testWithCallout(final Id leadId)
{
    System.debug(DateTime.now().format('m:s') + ': Lock requested');
    final Lead lead = [Select id From Lead where id = :leadId FOR UPDATe];
    System.debug(DateTime.now().format('m:s') + ': Lock acquired');

    final HttpRequest req = new HttpRequest();
    req.setEndPoint('https://www.google.de');
    req.setMethod('GET');
    final Http http = new Http();
    http.send(req);

    for(Integer i = 0; i < 30000000; i++) {} 

    System.debug(DateTime.now().format('m:s') + ': Done');

}

And here is the result without callout:

Execution 1: 
16:56: Lock requested
16:56: Lock acquired
17:02: Done

Execution 2:
16:59: Lock requested
17:59: Lock acquired
17:17: Done

You can see that Execution got the lock when Execution 1 is finished!

And here is the result with callout:

Execution 1: 
21:18: Lock requested
21:18: Lock acquired
21:34: Done


Execution 2:
21:23: Lock requested
21:23: Lock acquired
21:38: Done

You can see that Execution 2 started eventhough Execution 1 is not finished yet !

What Problem do I want so solve

We have a link including a lead id. If you click the link the following will happen:

  • the lead will be lookuped up
  • propagated to an external system
  • converted to account/contact

What will happend if you click the link immediately twice? The hole process will be executed twice!

That's why I want to lock the record.

I need the lock because i only want to make the callout once! How can you solve this problem? Any ideas?

  • Most likely WAD which is why you cannot do DML and then make a callout. – Eric Dec 4 '16 at 0:53
  • What's WAD? Yes, DML and then callout is not allowed. But the example don't give me that error. Also it isn't described anywhere that the lock gets released. – r2ric Dec 4 '16 at 9:32
  • Working as designed. And I never said you got that error. If you only want to make the callout once, you will have to rethink your design. Should not be designing flow control of a process around a database lock.....IMHO - I believe the lock is released whenever you make a callout – Eric Dec 4 '16 at 16:30
  • What other solution do we have? I could think of some Async Job. First retrieve the Object; mark it as processed and then do async processing which does the callouts. I think this solution would be just an workaround to solve the problem. – r2ric Dec 4 '16 at 19:54
  • 1
4

This is described in Known Issue W-2814934: Callouts within SELECT FOR UPDATE

Salesforce already forbid database operations before callouts. Their motivation being to prevent resource hogging. The behaviour of SELECT FOR UPDATE might be enforced in the same spirit.

Imagine one HTTP callout that takes 60 seconds to respond. This is an unreasonably expensive in terms of holding database snapshots, transactions, record locks, etc in the shared infrastructure.

To quote Daniel Ballinger:

Locks have to reach across threads. Otherwise they can't do what they need to. Using SELECT FOR UPDATE won't prevent race conditions as expected during web service callouts.

FOR UPDATE is especially expensive on shared infrastructure; it may stall any number of threads! Thus:

  • Salesforce could nail your HTTP callout just like they do for DML, 'uncommitted work' ... or
  • Salesforce could invalidate your lock to preserve a clean DML context (which they seem to do)
0

Just a thought - You've designed it so that it immediately goes and makes a callout upon clicking a certain link and then it makes a database update when the callout comes back. And you have found that there's a risk of clicking it twice. Why not change the design so it is impossible to click it twice?

If this link (Preferably a button? Buttons tend to imply actions rather than just going somewhere) is on a Visualforce page you can set a flag in the controller. The method that executes on the click would check for the flag and do nothing if the flag has already been flipped, and if it hasn't, then before the callout it would flip the flag.

If this link/button is on a record, perhaps you could embed a small custom Visualforce piece in the page layout that contains said link/button so that the controller can ensure it does not to run twice. Or you could have a link/button from the record navigate to a Visualforce page with the confirmation.

Something similar would be possible in Lightning components as well, but this time the client-side controller would be the one guarding against multiple callouts.

  • Not a bad idea but I still think the trigger to send the callout should be the conversion and not prior to that. The OP never said in their question that the conversion happened as a result of the response being received. If the conversion always happens then that should be the trigger, if the conversion is conditional based not he response then taking steps to ensure the link is not clicked twice (modal, vf page, disable, etc) would be appropriate – Eric Dec 5 '16 at 2:02
  • True, the OP did not clarify whether the conversion depends on the response or not. I made an assumption based on the fact that "propagated" was the second bullet point and "converted" was the third. However, regardless of the use case, we know we don't want the action to be triggered twice from the same user in the same session, because we don't want to attempt either of the same conversion or the same callout more than once. – Charles T Dec 5 '16 at 15:05

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.