4

I am trying to make sense of a Salesforce help article. I can't understand why the example they give here does not fail. The second fails because there is a callout (#3) after DML (#2). But why doesn't their first example also fail, between #5 and #6?

Following the steps in this order will work

  1. query
  2. callout
  3. query
  4. callout
  5. insert
  6. callout <-- why doesn't this fail?
  7. callout
  8. callout
  9. insert or update

The following scenario of steps will fail :-

  1. callout
  2. insert
  3. callout <---- fails here

Conceptually, I understand that DML operations will open a transaction that won't be committed until after triggers etc at the end of a transaction run order, and that I can't make a callout during this window. Usually I get around this by using an @future method to move the processing to an asynchronous context. But sometimes I still get stuck like a case where I need to update, say, a counter variable/setting for maintaining a running index. In this case I need to increment this custom setting and make a callout to return a UI message of the user. What is the best method to do this? Some different code organization I'm not thinking of? The Streaming API (I am not very familiar with this)? The uncommitted work error doesn't make a ton of sense to me.

2
  • 1
    This is a confusing help doc that talks about multiple scenarios and doesn't clarify. DML before callout will fail.
    – identigral
    May 18, 2023 at 19:33
  • 2
    You are right. I left a thumb-down feedback on that help article to call out the error. May 18, 2023 at 19:44

1 Answer 1

1

The help topic is definitely wrong. Unlike the official documentation, those topics are not curated as closely. You are correct that, given the example, step 6 will throw the exception you'd expect. The standard method is to callout first, then update any records, as you'd expect. You can use a continuation if you don't mind your callout being asynchronous (e.g. for Visualforce or LWC), and queueable/future methods are indeed viable choices. In the meantime, you may want to submit a ticket to see if the wording/example can be clarified.

4
  • I haven't used a continuation in an LWC before. What is the benefit? If you call an Apex method from an LWC, it won't block the UI right? Isn't it automatically asynchronous, unless I choose to await the Promise response?
    – Xaphy123
    May 18, 2023 at 20:37
  • 1
    @Xaphy123 Calls to Salesforce are always asynchronous with respect to the client, even with await, which is merely an illusion of synchronous code. Continuations, however, will make Apex asynchronous as well--your server code will initialize faster, providing an initial state sooner. Imagine a callout that takes 2 minutes to complete. Without Continuation, your initial state won't be loaded for the entire time. With it, your initial state loads nearly immediately, then you get the rest of the data when the callout completes.
    – sfdcfox
    May 18, 2023 at 20:52
  • Thanks so much. Do you recommend something I could read to understand what you mean by only providing "an illusion of synchronous code"? If I'm using an await, what's the core difference that makes it not synchronous in reality vs just an "illusion"
    – Xaphy123
    May 18, 2023 at 22:23
  • @Xaphy123 See my example. methodA reads more like synchronous code; the only clue is the async and await keywords, while methodB looks "stranger", having a then method being called from another method. It's easy to reason about this in such a small example, but in a huge function with dozens of lines, it can be harder to reason about which parts are async with regards to other parts.
    – sfdcfox
    May 19, 2023 at 2:22

You must log in to answer this question.

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