Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symfony\Component\Process\Exception\ProcessTimedOutException on PDF generation #169

Closed
sn0opr opened this issue Jul 14, 2015 · 33 comments
Closed

Comments

@sn0opr
Copy link

sn0opr commented Jul 14, 2015

I'm using Laravel Snappy package, and I think the problem is from Snappy itself.
In my localhost (Windows 7 32bit) wkhtmltopdf 0.12.2.3 (with patched qt) everything is working fine.
In the deployment machine (Windows Server 2012 R2 64bit) wkhtmltopdf 0.12.2.4 64bit, it takes about 60 seconds without any response or error... Good news I'm using Bugsnag service to track bugs and errors, and this is what I get:
Symfony\Component\Process\Exception\ProcessTimedOutExceptionGET /gca/public/demandes-achat/1138/pdf The process "C:\xampp\htdocs\gca/wkhtmltopdf/bin/wkhtmltopdf.exe --lowquality "C:\Windows\TEMP\knp_snappy55a4f9ff7f5862.10272127.html" "C:\Windows\TEMP\knp_snappy55a4f9ff7fab55.21457299.pdf"" exceeded the timeout of 60 seconds.
But when I tested to generate pdf from a website like google, it works fine !, with a plain html it wroks fine too.
I'm getting crazy here because it's working on my dev machine Win 7 and my computer Win 8.1 with difference wkhtmltopdf version for sure...

Btw, I'm using Bootstrap.min.css and Fontawesome.css

Please help me it's urgent.

@akovalyov
Copy link
Contributor

@sn0opr I have good news and bad news for you.
Good news is that we are here to help
Bad news is that we can not.
60 seconds is default timeout for Symfony/Process. Your error means that in 60 seconds there was no response from wkhtmltopdf. In this case the only thing is possible - networking issues. Generating pdf from local html or google website will work since it is loaded fastly. Please, check the url which you are trying to fetch. And remember that not only the html itself should be loaded in 60 seconds but all the resources which that html contains.
If you just want to increase the timeout - you can set it here -

* Sets the timeout. Be aware that option only works with symfony
. If you want to do that - please, consider that you use the latest snappy version.
Cheers.

@docteurklein
Copy link
Contributor

@sn0opr My guess is that it comes from wkhtmltopdf, not snappy.
You should try to execute the exact same command that the application generates (look at the logs or var_dump it in AbstratGenerator), and try to execute it in a shell, on the production server.

@sn0opr
Copy link
Author

sn0opr commented Jul 14, 2015

@akovalyov Hi, thank you for the fast reply.

1 - I'm generating pdf from local resources
2 - I'm only loading 3 css files (bootstrap.min.css, fontawesome.min.css and a small css file that made for my pdf pages)
3 - @docteurklein I tried the wkhtmltopdf.exe program using the command line and it works like expected, I uses the same html page and It converts in about 2 seconds not more.

4 - I removed the css files from the <head> to try if the resources are making the issue, and yeah It worked, but without any css file.. Now I'm confused..., how it works with command line without any issue but not with the Snappy class.

5 - I tried the Symfony class Symfony\Component\Process\Process and run the command myself ```, same thing, it's not working in Windows Server 2012 but it works in Win 7 and Win 8! :

$binary = \Config::get('snappy.pdf.binary');
    $process = new Symfony\Component\Process\Process($binary.' '.url('demandes-achat/1024/pdf').' test.pdf');
    $process->run(function ($type, $buffer) {
        if (\Symfony\Component\Process\Process::ERR === $type) {
            echo 'ERR > '.$buffer;
        } else {
            echo 'OUT > '.$buffer;
        }
    });

The Win Server machine is 12GB of RAM and Xenon Processor

@docteurklein
Copy link
Contributor

Interesting: So it's definitly a problem with the Process execution. You can try to find existing issues on https://github.com/symfony/symfony/issues?q=is%3Aopen+is%3Aissue+label%3AProcess

@akovalyov
Copy link
Contributor

@sn0opr have you tried to execute wkhtmltopdf command manually in Windows cmd?

@sn0opr
Copy link
Author

sn0opr commented Jul 14, 2015

@akovalyov Like I said, yes I did and it's works perfectly, I changed my pdf script from returning pdf file with Snappy to returning html file and tested with command line, it dose the job in a very small time. here is the output:

PS C:\xampp\htdocs\gca\wkhtmltopdf\bin> .\wkhtmltopdf.exe http://localhost/gca/public/demandes-achat/1138/pdf processs.pdf
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

@docteurklein
Copy link
Contributor

@sn0opr you can try to narrow the problem:

try with php -a:

proc_open($cmd,
    array(
        array("pipe","r"),
        array("pipe","w"),
        array("pipe","w")
    ),
$pipes);

@sn0opr
Copy link
Author

sn0opr commented Jul 14, 2015

@docteurklein thank you for trying to help me,
I just tried with the native php exec() method and It worked like expected!!!
So the problem is from the Symfony\Component\Process\Process class !

//var_dump(exec($binary.' http://localhost/gca/public/demandes-achat/1138/pdf rihane.pdf'));
//exec method works fine and outputs the file like expected
    proc_open($binary.' http://localhost/gca/public/demandes-achat/1138/pdf rihane.pdf',
    array(
        array("pipe","r"),
        array("pipe","w"),
        array("pipe","w")
    ),$pipes);
    var_dump($pipes);

result:
array(3) { [0]=> resource(86) of type (Unknown) [1]=> resource(87) of type (Unknown) [2]=> resource(88) of type (Unknown) }

@docteurklein
Copy link
Contributor

for proc open, you should use:

var_dump(array_map('stream_get_contents', $pipes));

Also, proc_open doesn't return anything, but you can still look at the file rihane.pdf and see if it worked.

@docteurklein
Copy link
Contributor

So, if proc_open fails, then it's a problem with php's http://php.net/proc_open.
You can try to search for solutions there.

@docteurklein
Copy link
Contributor

@sn0opr
Copy link
Author

sn0opr commented Jul 14, 2015

@docteurklein sorry for the late, I tested with array_map function and I got an error:

$binary = \Config::get('snappy.pdf.binary');
    proc_open($binary.' http://localhost/gca/public/demandes-achat/1138/pdf xxx.pdf',
    array(
        array("pipe","r"),
        array("pipe","w"),
        array("pipe","w")
    ),$pipes);
    var_dump(array_map('stream_get_contents', $pipes));

Output :

stream_get_contents(): 86 is not a valid stream resource

I forgot to say that the pdf file is generated successfully with ```proc_open```

@sn0opr
Copy link
Author

sn0opr commented Jul 15, 2015

@docteurklein @akovalyov , I just found a solution.
I got to the source code of Snappy package and found in the AbstractGenerator::executeCommand() method that you use your own Process class if Symfony Process class dosen't exist, so I just remove this condition and used Snappy's Process class, and it worked like a charm!:

protected function executeCommand($command)
    {
        /*if (class_exists('Symfony\Component\Process\Process')) {
            $process = new \Symfony\Component\Process\Process($command, NULL, $this->env);
            if ($this->timeout !== false) {
                $process->setTimeout($this->timeout);
            }
        } else {
            $process = new Process($command, $this->env);
        }*/

        $process = new Process($command, $this->env);
        $process->run();

        return array(
            $process->getExitCode(),
            $process->getOutput(),
            $process->getErrorOutput(),
        );
    }

Can you please provide an option to use Symfony's Process class or the default one ?.
Thank you for the support

@docteurklein
Copy link
Contributor

see #166

@akovalyov
Copy link
Contributor

@sn0opr you can install it as dev-master if you use composer

@osaris
Copy link

osaris commented Aug 17, 2015

I don't get the point, looks like @sn0opr say that it works with the Process class from snappy and you removed it in #166 to force usage of the one from Symfony ?

I have the same problem and using 0.4 and forcing snappy to use its own Process class works for me too. It's also a lot more faster (for the same HTML, something like 2 seconds between the button click and the PDF show with your Process class and more than 4 seconds with Symfony Process class).

@akovalyov
Copy link
Contributor

@osaris thank for the feedback. Could you give a little bit more of details about the environment and the input options for Snappy? For how many iterations have you launched it?
I will setup a test env later this week on Linux to see an compare the execution time.

@jeremyb do you still have Windows env to test the Snappy performance with Symfony/Process? :)

@osaris
Copy link

osaris commented Aug 17, 2015

@akovalyov on my dev machine (OSX), on 5 runs with the same HTML to convert to PDF the time is very similar.

On our production environment (Windows 2008 R2, Apache 2.4, PHP 5.6.10, Laravel 5.1), I need to remove the css link to have it working with Symfony2 Process (it's ok with Snappy Process class), but the results are very different, on 10 runs with Snappy Process class, average speed is 561ms to get the PDF, with Symfony2 Process class it's 2.61 seconds !!

Despite the performance issue, my main problem is that I can't use css link If I use the Symfony2 Process class but it's ok with Snappy Process class.

@pilot
Copy link
Contributor

pilot commented Aug 17, 2015

+1 to have abiltiy to chose type of processor, symfony or native

@sn0opr
Copy link
Author

sn0opr commented Aug 19, 2015

+1

@docteurklein
Copy link
Contributor

Interesting. We removed the embedded Process class because iti didn't work well on many setups.
And I really think we should leverage a well tested library like Symfony's Process, even tho it seems to not work in some cases.

The best would be to concentrate on fixing it, not snappy.

@osaris
Copy link

osaris commented Aug 19, 2015

@docteurklein make sense for me, the related issue on symfony part seems to be this one : symfony/symfony#15278

@docteurklein
Copy link
Contributor

BTW, you could try to put enhanceWindowsCompatibility to false, just to try.

@osaris
Copy link

osaris commented Aug 19, 2015

@docteurklein can I change this setting in my snappy configuration file or somewhere else in my app ?

@akovalyov akovalyov reopened this Aug 19, 2015
@osaris
Copy link

osaris commented Aug 22, 2015

Sorry for the delay.

enhanceWindowsCompatibility don't change anything. Same for bypass_shell and suppress_errors.

@WouterSioen
Copy link
Contributor

I have the same issue with the process component (see symfony/symfony#15278 (comment))

It would be awesome to be able to choose the old Snappy Process class instead of the Symfony Component.

@WouterSioen
Copy link
Contributor

I only have this issue when I pass on my PHPSESSID cookie to the process.

$snappy->setOption(
    'cookie',
    [ 'PHPSESSID' => $this->request->cookies->get('PHPSESSID') ]
);

The generated pdf is correct though. It's just the Symfony Process that isn't stopping with this option.
I guess this means that it's a wkhtmltopdf issue?

I don't yet know why the Symfony Process fails on it though.

@WouterSioen
Copy link
Contributor

Hmm, it seems like the script is in fact hanging, since the pdf is only written after the timeout has been reached (and the script is thus terminated using a termsign 15.

The pdf looks correct though, and the exact same command runs perfectly on the CLI.

I've now worked around it using

use Symfony\Component\Process\Exception\ProcessTimedOutException;

$snappy->setTimeout(3);
try {
    $snappy->generate($input, $output);
} catch (ProcessTimedOutException $e) {
    // do nothing, the pdf is probably generated
}

It's not that clean, because other reasons the process timed out aren't handled anymore, but it works for now (if the pdf is generated in 3 seconds)

@osaris
Copy link

osaris commented Jan 27, 2016

FYI, my problem was that some external links (CSS etc) weren't accessibles from the server that is running wkhtmltopdf (DNS misconfiguration). wkhtmltopdf is really slow to give up on missing ressources so the generation time was over 30 sec.

I fixed the problem by using realpath() to use local path for these ressources.

@barryvdh
Copy link
Contributor

Again returning to this issue, I suddenly only get timeouts (existing project), but the files are generated.

Replacing the Symfony Process in the AbstractGenerator fixed it, so not sure why the Symfony Process is not responding..

protected function executeCommand($command)
    {
        exec($command, $output, $status);

        return array($status, $output, $status == 0 ? '' : $output);
    }

@CharlyPoppins
Copy link

On our dedicated the timeout issue was solved by disabling ipv6.

@akerouanton
Copy link
Contributor

I close this issue because it is pretty old now and the only updates in the past year is about networking issues leading to timeouts. If you still face a similar problem please open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants