Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dcranmer's avatar

Intermittent cancellation generating PDF with Browsershot

This is a followup to a previous thread, but with a new issue. In brief, the sequence outlined below goes without a hitch maybe half the time. But intermittently (in both Chrome and Firefox), the generate method below is listed as "cancelled" in dev tools, and returns back to the original page with the form that submits the post request. Inertia shows that form.wasSuccessful is false, but there are no errors. I've tried using callbacks on the submit() method, but they don't do or show anything.:

const submit = () => {
  console.log('at submit')
  form.post(route('auth.report.generate'), {
    onSuccess: () => console.log('success'),
    onError: () => alert("error"),
    onInvalid: () => alert("invalid"),
    onStart: () => console.log('start'),
    onCancel: () => alert("Cancelled")
  });
};

I'm not sure how to coax more information from inertia regarding the request cancellation. If there were a validation error, that should be showing up in the form object. In Dev Tools, I can see the payload of posted data for generate. The only other "clue" I've noticed is that the flash message (see below) appears on the original form page. Here is a more detailed description of what I am doing:

I have a form that uses useForm() and posts list of data items to a route pointing to a generate() controller method that 1) uses a form request to validate the posted data; 2) saves the posted pdf file name to the session; 3 sets the path to where the pdf will be saved; 3)saves the pdf with Browsershot; 5)redirects to an "success" inertia page that contains a link for viewing and downloading the pdf. The redirect also sets a success flash message for the success page to display.

//build `$data` array from posted data
$data[].....
// format: assembly-7-2022-47YzsWE.pdf
        $pdfFile = $data['report_file_name'];
        // save computed file name to session for use in showPdf()
        session(['districtPdfFile' => $pdfFile]);

        // /storage/app/public +file name
        $pdfPath = storage_path('app/public/'.$pdfFile);

        // html view of report
        $html = view('reports.pdf-report', $data)->render();

        // Generate pdf and save to /storage/app/public & /public/storage/
        Browsershot::html($html)->setNodeBinary(config('constants.node_bin').'node')->setNpmBinary(
            config('constants.node_bin').'npm'
          )->showBackground()->setOption('newHeadless', true)->savePdf($pdfPath);

        // redirect to success page, which contains link to showPdf() method to show/download pdf
        return redirect()->route('auth.report.success')->with([
          'message' => 'District or County Report generated successfully.'
        ]);

The link on the success page points to a controller method showPdf that retrieves the file name from the session and returns a response for viewing (and downloading) the pdf:

public function showPdf()
    {
        // NOTE: /storage/app/public and public/storage are symlinked

        // retrieve computed file name from session
        if (session('statewidePdfFile')) {
            $pdfFile = session('statewidePdfFile');
        } elseif (session('districtPdfFile')) {
            $pdfFile = session('districtPdfFile');
        } else {
            abort(404);
        }


        // check whether file is present in /storage/app/public
        if (Storage::disk('public')->exists($pdfFile)) {
            $filePath = Storage::disk('public')->path($pdfFile);

            // return file in browser as pdf
            // file can be downloaded from /public/storage
            return response()->file($filePath, [
              'Content-Type' => 'application/pdf',
              'Content-Disposition' => 'inline; filename="' . $pdfFile . '"'
            ]);
        } else {
            abort(404);
        }
  }
0 likes
1 reply
LaryAI's avatar
Level 58

It seems like the issue you're experiencing with intermittent cancellation of the PDF generation process could be related to a timeout or resource limitation when Browsershot is trying to generate the PDF. Since Browsershot relies on a headless browser (usually Puppeteer, which in turn uses Chrome), the process can be resource-intensive and may take longer than expected, especially if the HTML content is complex or large.

Here are a few steps you can take to troubleshoot and potentially resolve the issue:

  1. Increase Execution Time: Make sure that your PHP script has enough time to execute the Browsershot command. You can increase the maximum execution time by setting the max_execution_time in your php.ini file or temporarily within your script using set_time_limit().
set_time_limit(300); // Increase the limit to 5 minutes
  1. Increase Memory Limit: Similarly, ensure that PHP has enough memory allocated to handle the operation. You can increase the memory limit in your php.ini file or within your script:
ini_set('memory_limit', '512M'); // Increase PHP memory limit
  1. Check Browsershot Timeout: Browsershot has its own timeout settings. Make sure you set a timeout that is sufficient for the PDF generation to complete.
Browsershot::html($html)
    ->timeout(60000) // Set timeout to 60 seconds
    ->savePdf($pdfPath);
  1. Check for JavaScript Errors: If your HTML view (reports.pdf-report) includes JavaScript that needs to be executed for rendering, make sure there are no JavaScript errors that could cause the headless browser to hang or fail.

  2. Check Server Logs: Look at your web server and PHP error logs to see if there are any relevant messages that could indicate what's causing the intermittent failures.

  3. Debug Browsershot: You can enable debugging in Browsershot to get more information about what's happening during the PDF generation process.

Browsershot::html($html)
    ->setNodeBinary(config('constants.node_bin').'node')
    ->setNpmBinary(config('constants.node_bin').'npm')
    ->showBackground()
    ->setOption('newHeadless', true)
    ->setOption('debug', true) // Enable debugging
    ->savePdf($pdfPath);
  1. Check Network Issues: Since the issue is intermittent, it could be related to network instability. Make sure your server has a stable connection, especially if it's making external requests as part of the PDF generation process.

  2. Optimize HTML Content: If the HTML content is very large or complex, try to simplify it. Remove unnecessary elements, scripts, and styles to see if that helps with the PDF generation.

  3. Update Browsershot and Dependencies: Ensure that you are using the latest version of Browsershot and its dependencies, as updates may contain fixes for issues like the one you're experiencing.

  4. Asynchronous Processing: If the PDF generation is still failing intermittently due to resource constraints, consider offloading the task to a queue and processing it asynchronously. This way, the user is not waiting for the PDF to generate synchronously, and you can handle retries in case of failure.

// Dispatch a job to generate the PDF asynchronously
GeneratePdfJob::dispatch($data);

Remember to test each change individually to identify which one has an impact on the issue. If none of these suggestions resolve the problem, you may need to provide more detailed logs or error messages to further diagnose the issue.

Please or to participate in this conversation.