3

I'm trying to generate a PDF, and in normal Apex execution the function is haulted due to CPU timeout (exceeding 10 second execution time).

So I tried using @future annotation to use Asynchronous Apex since with Winter '16 we can uyse getContent() and getContentAsPDF() in Asynchronous Apex.

My code looks like this:

public void makePDF() {
    MyClass.generatePDF(con.getId(), arecord.Name);
}

@future(callout=true) 
public static void generatePDF(Id recId, String recName) {
    PageReference pageRef = Page.StmtPDF;
    pageRef.getParameters().put('stmtid', recId);
    Blob b = pageRef.getContentAsPDF();
    Attachment att = new Attachment();
    att.Body = b;
    att.Name = recName +'.pdf';
    att.ContentType = 'application/pdf';
    att.ParentId = recId;
    insert att;
}

I keep getting same Apex CPU timeout exceeded exception at around 14 second.

May be I'm understanding it incorrectly, but shouldn't I get 60 second timeout in @future method for executing PDF content?

Or my approach is flawed in some way?

== EDIT ==

What does this CRUC update do? - “PageReference getContent() and getContentAsPDF() Methods Behave as Callouts” Critical Update Postponed - Release Notes says that auto-activate date is postponed and not the update. Am I correct in reading that?

enter image description here

2 Answers 2

6

getContentAsPDF actually internally performs a callout back into Salesforce as a new transaction. This means that the actual CPU time used for the primary transaction doesn't account for the time used generating the PDF, and it gets its own governor limits.

Proof:

Class

public class vfWait5 {
    public vfWait5() {
        Long start = DateTime.now().getTime();
        while(DateTime.now().getTime()-start<5000);
    }
}

Page

<apex:page controller="vfWait5">
</apex:page>

Execute Anonymous

Page.vfWait5.getContentAsPDF();

Cumulative Usage for Execute Anonymous

  Number of SOQL queries: 0 out of 100
  Number of query rows: 0 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 0 out of 150
  Number of DML rows: 0 out of 10000
  Maximum CPU time: 2 out of 10000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 100
  Number of Email Invocations: 0 out of 10
  Number of future calls: 0 out of 50
  Number of queueable jobs added to the queue: 0 out of 50
  Number of Mobile Apex push calls: 0 out of 10

Cumulative Usage for vfWait5

  Number of SOQL queries: 0 out of 100
  Number of query rows: 0 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 0 out of 150
  Number of DML rows: 0 out of 10000
  Maximum CPU time: 4329 out of 10000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 100
  Number of Email Invocations: 0 out of 10
  Number of future calls: 0 out of 50
  Number of queueable jobs added to the queue: 0 out of 50
  Number of Mobile Apex push calls: 0 out of 10

Notice how I only generate 2 ms of execution time for a 5 second page render. The actual PDF page generates a separate log, where you'll see the ~5000 ms CPU time used. Also, you'll notice it has a normal 10000 ms limit (actual limit is, of course, flexible, but will probably never exceed 25000 ms).

So, in summary, you can never render a PDF that requires more than 10 seconds to render, even in asynchronous code. You can, however, render a pretty much unlimited number of PDFs that would far exceed the normal 60000 ms limit of asynchronous processes using this technique.

If you really wanted to do this, I'd suggest rendering the HTML in asynchronous code, save it to a Document/Attachment, then chain to a new asynchronous block and gather that data using a page that just echos the contents of a file into the page. You'll want to use Queueable or Batchable so you can get two chained transactions in order for this to work.

3
  • How do you suggest rendering the HTML in asynchronous code? If its using a VF page rendered as HTML, won't that run into the same issue? Commented Jun 24, 2021 at 16:58
  • Maybe I can split up the job into multiple html visualforce pages and them append them all to a pdf. ughh Commented Jun 24, 2021 at 17:03
  • @MenachemShanowitz You can render the code in your async code, and then pass it in as a URL parameter, possibly. I haven't thought about this approach too closely
    – sfdcfox
    Commented Jun 24, 2021 at 19:31
0

Please visit the below link:

https://releasenotes.docs.salesforce.com/en-us/summer16/release-notes/rn_cruc.htm?edition=&impact=

This update has been postponed until Winter'17

8
  • There is a critical update for this mentioned item in my org. Eve if I activate it or deactivate it, there is no change in timeout. My function call gets timed out in around 14 seconds instead of 60 seconds. My understanding on this was, before Winter '16, when we use getContentAsPDF(), we were getting exception that callouts don't support this method call, which is not happening currently, but function call is getting executed but CPU timeout is not being picked for Async apex.
    – VarunC
    Commented Jul 29, 2016 at 13:19
  • Since these methods are not treated as callouts, so the synchronous transaction limit is applied on them(which is 10 seconds).That is why, you are getting that issue
    – Abhijeet
    Commented Jul 29, 2016 at 13:20
  • hmm .. makes sense, but I'm seeing a CRUC update for exactly this thing mentioned in Release Notes. I think the notes says that auto-activation date has been postponed and not the CRUC itself (updated my question with CRUC screenshot).
    – VarunC
    Commented Jul 29, 2016 at 13:26
  • The update was rolled out but not activated as of yet.InWinter 17, salesforce could auto-activate it then.
    – Abhijeet
    Commented Jul 29, 2016 at 13:32
  • For how many records are you trying to use this method? is it a single record?
    – Abhijeet
    Commented Jul 29, 2016 at 13:33

You must log in to answer this question.

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