4

why is my queue job timing out? I am using database as a driver I tried the following:

class PdfGenerator implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $userData;
    protected $filename;
    protected $path;
    public $timeout = 1200;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($userData, $filename)
    {
        //
        $this->userData = $userData;
        $this->filename = $filename;
        $this->path = \public_path('\\pdfs\\'.$this->filename.'.pdf');
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $pdf = App::make('snappy.pdf.wrapper');
        $footer = \view('supporting.footer')->render();
        $header = \view('supporting.header')->render();
        //$userData = \collect([$this->userData[1]]);
        $pdf->loadView('order_clean', ['users' => $this->userData])
        ->setOption('margin-top', '20mm')
        ->setOption('margin-bottom', '20mm')
        ->setOption('minimum-font-size', 25)
        ->setOption('header-html', $header)
        ->setOption('footer-html', $footer);
        $pdf->save($this->path);
    }
}
php artisan queue:work --timeout=1200
php artisan queue:listen --timeout=0

yet my queue job still fails due to timeout of 60s according to the logs because the symfony process timed out. I am not using supervisor yet, just trying out how the queue works from the console

edit:: controller code + blade code controller code:

class OrderController extends Controller
{
public function renderPDF()
    {
        $user_data = $this->getUserData();
        $filename = 'test '.\now()->timestamp;
        //no timeouts here
        //if not ran on queue and with set_time_limit, takes around 70s
        //at current data size
        $this->dispatch(new PdfGenerator($user_data,$filename));
        //view returns successfully
        return \view('test.test', ['filename'=>$filename]);
    }
}

Blade file:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Order Layout</title>
    <style>
        *{
            font-family: cursive;
        }

        .wrapper {
            display: block;
        }

        .invoice {
            display: block;

            width: 80%;
            margin: 0 auto;
            margin-top: 10px;
            padding-top: 10px;
            padding-bottom: 10px;
            background: #d3d3d3;
            page-break-inside: avoid !important;
            padding-left: 20px;
        }

        .order-items {
            padding-left: 100px;
        }

        .table {
            width: 90%;
            align-self: center;
            border: 1px solid black;
            orphans: 15;
        }

        .table>* {
            text-align: center;
        }
    </style>
</head>

<body>

    <main class="wrapper">
        @foreach ($users as $user)

        @php
        $orders = $user->orders //just for renaming
        @endphp
        @foreach ($orders as $order)
        
        <div class="invoice">
            @php
            $sum=0;
            @endphp
            <h2>{{$user->name}}: {{$order->id}}</h2>
            <div class="order-items">
                <table class="table" border="1">
                    <thead>
                        <tr>
                            <th>Product Name</th>
                            <th>Unit Price</th>
                            <th>Qty</th>
                            <th>subtotal</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach ($order->products as $product)
                        <tr>
                            <th>
                                {{$product->name}}<br>
                                {{$product->name}}<br>
                                {{$product->name}}<br>
                                {{$product->name}}<br>
                            </th>
                            <td>{{$product->unit_price}}</td>
                            <td>{{$product->pivot->quantity}}</td>
                            @php
                            $sum+= $product->pivot->quantity*$product->unit_price
                            @endphp
                            <td>{{$product->pivot->quantity*$product->unit_price}}</td>
                        </tr>
                        @endforeach
                    </tbody>
                    <tfoot>
                        <tr>
                            <th colspan="3">Total:</th>
                            <td>{{$sum}}</td>
                        </tr>
                    </tfoot>
                </table>
            </div>
        </div>
        @endforeach
        @endforeach
    </main>
</body>

</html>
Ali
  • 406
  • 5
  • 15
  • Perhaps your job is calling another script that is timing out due to your server's `max_execution_time` setting. If so, please try adding `set_time_limit(1200)` to the top of your processing script or long running function. – Wesley Smith Oct 13 '20 at 04:03
  • Yes, I am doing an intensive task on it. I thought the queue was made for that (as in i dont have to fiddle with time limits). Guess i was wrong, i will try that later, thanks – Ali Oct 13 '20 at 04:09
  • In some cases it probably does, but depending on how that other task is started or whatever, the timelimt set by the initializing queue job may not affect that other script, as an example, if the queue job performed a curl request to another script, that execution wouldnt know anything about the timelimit set by the queue, etc... Hard to say without seeing exactly what the job does and how, but thats where I'd put my money – Wesley Smith Oct 13 '20 at 04:12
  • What the job does is just receive a huge collection (as constructor parameter) and use the snappy library (wrapper to wkhtmltopdf) to make a pdf out of it and save it in a predetermined path – Ali Oct 13 '20 at 04:13
  • Hmm, if all that happens inside the queue logic Id expect the timeout to work as you have it. Perhaps if you post the full queue code someone might spot the issue – Wesley Smith Oct 13 '20 at 04:15
  • 1
    alright, will update my question details – Ali Oct 13 '20 at 04:16
  • @WesleySmith I tried using set_time_limit(1200) in the handle method, it still timed out at 60s due to symfony process throwing a ProcessTimedOutException – Ali Oct 13 '20 at 04:24
  • Hmm, that doesnt _seem_ like a long running task. Is there some logic inside the `order_clean` view itself maybe? – Wesley Smith Oct 13 '20 at 04:26
  • Or is the long running process the part that gets the `$userData, $filename` and passes them to this class? Where does that happen exactly? If thats happening outside this class, then the timeout for this class wont affect that execution – Wesley Smith Oct 13 '20 at 04:28
  • nope, just a simple view that shows the fields of each userData object in a separate table (albeit huge ones), nothing out of the ordinary there. there is no styling there beyond table border and a simple background color, and no javascript. The outside class runs a query (doesnt take long, and doesnt time out) and passes them to the job via constructor. The pdf generation is what timeouts – Ali Oct 13 '20 at 04:29
  • side question: do you have the `pcntl` extension installed? – lagbox Oct 13 '20 at 05:51
  • @lagbox i dont think so – Ali Oct 13 '20 at 05:53
  • you need to have that extension installed to specify job timeouts ... from the command line you can check `php -m | grep pcntl` to see if its installed/enabled – lagbox Oct 13 '20 at 05:55
  • I dont remember seeing anything about it in the docs. I will try your suggestion when I'm able to. Thanks – Ali Oct 13 '20 at 06:00
  • 1
    there is a big red exclamation mark in the docs that says this in the Timeout section for queues – lagbox Oct 13 '20 at 06:01
  • Ohh my bad, somehow i missed it. – Ali Oct 13 '20 at 06:04
  • 1
    no worries, may not be the answer but you should make sure it is installed, good luck :) – lagbox Oct 13 '20 at 06:06
  • @lagbox I have installed ubuntu, and it worked like a charm. Please post is as an answer so i can accept it! – Ali Oct 16 '20 at 00:46
  • 1
    added an answer, have a great day – lagbox Oct 16 '20 at 06:52

1 Answers1

1

If you want to be able to set the timeouts you should make sure you have the pcntl PHP extension installed and enabled.

"The pcntl PHP extension must be installed in order to specify job timeouts."

Laravel 8.x Docs - Queues - Dispatching Jobs - Specifying Max Job Attempts / Timeout Values - Timeout

lagbox
  • 48,571
  • 8
  • 72
  • 83