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

Exception when deserializing FailedJob model #23168

Closed
ppalmtag opened this issue Feb 15, 2018 · 12 comments
Closed

Exception when deserializing FailedJob model #23168

ppalmtag opened this issue Feb 15, 2018 · 12 comments

Comments

@ppalmtag
Copy link

  • Laravel Version: 5.6.3
  • PHP Version: 7.1.11
  • Database Driver & Version: MariaDB 10.1.29

Info:

If you believe this is not something for the issue tracker, please close this issue and tell me!

Description:

I used to deserialize the FailedJob model in the failed_jobs table to display the filename the Job was processing. After upgrading to Laravel 5.5 to 5.6 this produces an Exception. I added the code I use below.

Steps To Reproduce:

foreach(\App\FailedJob::where('connection', 'transferftp')->get() as $job) {

	$payload = json_decode($job->payload);

	try {
		/* @var $create_product_export_files CreateProductExportFiles */
		$send_product_core_data = unserialize($payload->data->command);
		
		[...]

Results in

Type error: Argument 1 passed to Illuminate\Database\Eloquent\Builder::parseWithRelations() must be of the type array, null given, called in /var/www/html/oma/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php on line 1034

Symfony\Component\Debug\Exception\FatalThrowableError
…/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php 1075

Illuminate\Database\Eloquent\Builder parseWithRelations
…/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php 1034

Illuminate\Database\Eloquent\Builder with
…/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php 389

Illuminate\Database\Eloquent\Model load
…/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php 85

App\Jobs\SendProductCoreData restoreModel
…/vendor/laravel/framework/src/Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php 55

App\Jobs\SendProductCoreData getRestoredPropertyValue
…/vendor/laravel/framework/src/Illuminate/Queue/SerializesModels.php 45

App\Jobs\SendProductCoreData __wakeup
[internal]0

unserialize
…/app/Http/Controllers/UploadController.php 204

@sisve
Copy link
Contributor

sisve commented Feb 15, 2018

Your steps to reproduce isn't a complete code snippet we can use to reproduce it. Could you provide minimal working example we can use for this purpose?

@ppalmtag
Copy link
Author

Complete function I use in a Controller namen UploadController:

/**
 * Get jobs from the job queue and return an array with information
 * @return array
 */
private function getFailedJobs(): array {
    $jobs = [];
    foreach (\App\FailedJob::where('connection', 'transferftp')->get() as $job) {

        $payload = json_decode($job->payload);
        /* @var $create_product_export_files CreateProductExportFiles */
        $send_product_core_data = unserialize($payload->data->command);

        $matches = [];
        preg_match('/^.*:\s(.*)\sin.*$/', explode("\n", $job->exception)[0], $matches);

        $jobs[] = [
        'display_name' = json_decode($job->payload)->displayName,
        'created' = (new \DateTime($job->created_at))->format('d.m.Y H:i:s'),
        'filename' = $send_product_core_data->getFileName(),
        'message' = isset($matches[1]) ? $matches[1] : '-',
        ];
    }
    return $jobs;
}

FailedJob ist just an "empty" model refering to the table created by using php artisan queue:failed-table.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class FailedJob extends Model
{
    //
}

If you need more information, just ask.

@aaronhuisinga
Copy link

It looks to me that this issue is actually called from Jobs queued in Laravel 5.5 that are run after the 5.6 update (due to a delay on the queued job).

I'm not certain if it only happens if the queued model had a relationship or not, but we were seeing this after our update from 5.5 to 5.6 each time a job was attempted to be processed by the queue.

@aaronhuisinga
Copy link

It appears that jobs with relations queued in Laravel 5.6 have a "relations" property serialized with them, while in 5.5 they didn't. Thus when jobs queued in 5.5 are parsed in 5.6, this Exception is thrown.

@ppalmtag
Copy link
Author

I have tried to verify your assumption by clearing the failed jobs table and "creating" some new ones. Everything seems to work fine now. Thanks for the support, closing the issue now.

@vicgonvt
Copy link
Contributor

vicgonvt commented Feb 22, 2018

For anyone coming back to this issue, I was able to get all of my jobs to go through by following these steps. I made the modifications on my production server and then ran the jobs through. After I did that, I put everything back to how it ships with Laravel.

  • Open up vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
  • Find the method called public function with($relations) and replace it with the following modified method
    /**
     * Set the relationships that should be eager loaded.
     *
     * @param  mixed  $relations
     * @return $this
     */
    public function with($relations)
    {
        if (is_null($relations)) {
            $relations = [];
        }

        $eagerLoad = $this->parseWithRelations(is_string($relations) ? func_get_args() : $relations);

        $this->eagerLoad = array_merge($this->eagerLoad, $eagerLoad);

        return $this;
    }
  • Restart your Queue workers if you are running them already by running php artisan queue:restartin the terminal.

To explain this, when the jobs got queued in L5.5, the relations didn't exist in the queued job so when you try and run those old L5.5 queued jobs in L5.6, it throws an exception as they it's being set to NULL. This problem will only affect jobs that were queued in L5.5 for a later date and are now trying to be dispatched in L5.6. You will not need this modification after all of your L5.5 jobs are dispatched.

Please note: any new jobs dispatched in L5.6 will continue to work as expected and it will automatically add that new relations property.

Hope this helps anyone looking at this issue.

@sisve
Copy link
Contributor

sisve commented Feb 23, 2018

This sounds like something you should send a PR for. There will be many future upgrades of 5.5 to a newer version, and they may want their jobs to work...

@vicgonvt
Copy link
Contributor

@sisve I don't believe @taylorotwell would want this in the core as it is a temporary issue that only happens if you queued up jobs in L5.5 for a later date and have upgraded to L5.6 since then. It will go away once all of the jobs run.

@sisve
Copy link
Contributor

sisve commented Feb 23, 2018

I'm pretty sure this should be in the core. Even if it only happens when people upgrade; people will still upgrade from 5.5 to a newer release for another 2+ years since 5.5 is a LTS release.

Sure, maybe we shouldn't add a null-check to the Builder::with() method. How about using ->load($value->relations ?? []) in SerializesAndRestoresModelIdentifiers::restoreModel? Or perhaps avoid the call to ->load() entirely if the list of relations is null or empty?

public function restoreModel($value)
{
return $this->getQueryForModelRestoration(
(new $value->class)->setConnection($value->connection), $value->id
)->useWritePdo()->firstOrFail()->load($value->relations);
}

@aaronhuisinga
Copy link

@sisve That fix makes a lot of sense to me. I ended up adding a temporary hook to my deploy script to replace that file for the next few weeks to make sure no < 5.6 queued jobs are throwing exceptions. A fix in the actual framework would be welcome by me!

@sisve
Copy link
Contributor

sisve commented Feb 23, 2018

@vicgonvt This is your chance to get the Contributor flag! ;)

@vicgonvt
Copy link
Contributor

Submitted the PR in #23287

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

4 participants