7

Is there a way for @future annotated method to start execution before the synchronous request which invokes it has completed.

In other words, do I have some guarantees that the timing will look like this:

-start sync---call future---end sync---execute future->

instead of like this:

-start sync---call future---execute future---end sync->

I couldn't find the execution order guarantees in the documentation, although Future Methods states:

The reason why sObjects can’t be passed as arguments to future methods is because the sObject might change between the time you call the method and the time it executes. In this case, the future method will get the old sObject values and might overwrite them. To work with sObjects that already exist in the database, pass the sObject ID instead (or collection of IDs) and use the ID to perform a query for the most up-to-date record.

This can be read as saying that the future is not queued at the end of the transaction, otherwise Salesforce could guarantee that the sObject sent is the most recent version. And since it's queued during the transaction, it might imply that it also might execute and complete while the synchronous transaction is still running.

On the other hand, Does Database.rollback(savepoint) work with the Update method? implies that futures are only fired after the transaction completes:

Invoking Database.rollback not only rolls back inserts, but it goes much, much further. [...] It also rolls back:

Calls to @future methods. Any methods called within the rolled back part of your script will not be invoked (also why @future doesn't start until your script completes).

3 Answers 3

3

Things that are executed asynchronously are serialized into a binary format at the moment they are called, then placed into a queue. This queue is then executed later. I wrote a proof of concept for this once before, but I don't have it handy.

Therefore, it's easily possible that the records could change between the time the function is called and when it executes. For example, workflow field updates, rollup summary fields, and formulas might change by then.

It's generally better to query a record during execution of an asynchronously executed function rather than depending on it not changing between when it is queued and executed.

7
  • My question is basically when is "later". Do we have a guarantee that "later" is after the synchronous execution context, as you mentioned in your comment "Future methods are added to a queue. Records in this queue can't be processed until the final database save".
    – ipavlic
    Commented May 4, 2015 at 9:37
  • Future methods won't be called as part of the synchronous transaction and don't share governor limits, and failures won't stop the synchronous transaction. There's some optimization that allows future methods to run before a page load on a save, if there's resources, but it's still after the main transaction. More formally, the asynchronous methods won't run until the final commit and all locks are freed (in the UI case, the asynchronous code immediately re-acquires the lock).
    – sfdcfox
    Commented May 4, 2015 at 15:59
  • @sfdcfox, Do you have the proof of concept that you are referring to in this answer? Sorry for waking the zombie but I have been learning so much from your answers and curious and eager to see that POC..Thanks!
    – javanoob
    Commented Sep 6, 2015 at 23:16
  • @sfdcfox I am calling a future methods in afterUpdate call . When I Query the stuff in FutureMethods. It does not show me new values in the Query. That means Future call happens before afterUpdate data committed to database. I have also Query the lastmodifiedDate in Future call which is early then lastmodifiedDate on record. By all this , I think , I can conclude Future call happen before current synchronous execution/call. Commented Mar 8, 2017 at 20:31
  • @amidstCloud No, they definitely do not. I suspect that you're reading the logs incorrectly. I'd be glad to write some code that proves the point of my answer if you would like.
    – sfdcfox
    Commented Mar 8, 2017 at 20:39
1

From the Apex documentation: "Each future method is queued and executes when system resources become available." As such, if the system resources are available, the @future method could execute immediately.

I would conclude there are no guarantees the timing will look like the first timing order you asked about below:

-start sync---call future---end sync---execute future->

This is exactly why, as you've astutely noted, the documentation states:

The reason why sObjects can’t be passed as arguments to future methods is because the sObject might change between the time you call the method and the time it executes. In this case, the future method will get the old sObject values and might overwrite them.

Edited to add:

If you want to ensure the above mentioned timing order, you'd want to perform any DML before calling @future methods.

5
  • Sure, but I don't get how rollbacks would work if that were the case. I wrote a synchronous method that invokes an @future method and then forced an exception. The @future is not invoked. So even for implicit rollbacks (not invoked with Database.rollback), the @future call is rolled back, just as email sending.
    – ipavlic
    Commented Apr 3, 2015 at 10:21
  • I'd been wanting to get back to this post to add the edit above which I think is critical to achieving what you desire. We know that @future methods return void. Since they're spawned by the originating execution, that execution would still have a "hook" into them because of the pending return. I think that explains why an exception in the originating execution would roll them back.
    – crmprogdev
    Commented Apr 3, 2015 at 12:06
  • @crmprogdev , in this post: salesforce.stackexchange.com/a/28936/13265 @ca_peterson says that @future is executed after the script. Doesn't that mean that the order is always like: script -> future -> end ? Commented Apr 8, 2015 at 14:02
  • Future methods are added to a queue. Records in this queue can't be processed until the final database save. You cannot guarantee the maximum time until your method is called, but you can guarantee that it can't run before the transaction's final commit. This means after everything else; sending emails, updating rollup summary fields, everything. If you look at the Order of Execution document, future methods occur after the last step in that document.
    – sfdcfox
    Commented Apr 8, 2015 at 14:54
  • 1
    I just finished doing some searching and all I could find was the following video that includes some Best Practices for Asynchronous Apex titled Design Patterns for Asynchronous Apex that might be worth watching.
    – crmprogdev
    Commented Apr 8, 2015 at 15:31
-1

Use new APex queueable interface. In this way you can guarantee that sequence of execution even though the call will be asynchronous.

Check this out - Queueable interface details

2
  • Sorry, that was not my question.
    – ipavlic
    Commented Apr 2, 2015 at 12:52
  • Also this is incorrect! Queueables do not guarantee order. Only a Queable following a Queueable Guarantees order. I have proven this with failed executions and had to build an ordered queueable capability using queueables as the backbone. but in its raw form they are not ordered, based on creation time. and they can take minutes to execute, meaning many can queue up and be instantiated at the same or different times. Commented Apr 20, 2023 at 4:50

You must log in to answer this question.

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