14

I am trying to learn laravel database queue from its official documentation. I have done configuration as given in documentation .

Here my jobs :

<?php

namespace App\Jobs;

use App\SearchLog;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendTicket extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    protected $log;

    protected $searchLog = array();



    public function __construct(SearchLog $log , $data = array())
    {
        $this->log = $log;
        $this->searchLog = $data;
    }

     /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {

      $this->log->create($this->searchLog);     
    }

In my controller I call like this

public function store(Request $request)
{
 $searchLog = array();
 // searchLog contains the data to be inserted into database 
 $log = new SearchLog();
 $this->dispatch(new SendTicket($log , $searchLog));
 }

When I run the php artisan queue:listen I get the error like

[Illuminate\Database\Eloquent\ModelNotFoundException] No query results for model [App\SearchLog].

But when I edit the jobs like this

//only edited code 
public function __construct($data = array())
{
    $this->searchLog = $data;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
  SearchLog::create($this->searchLog);   
}

And when call from like this

 public function store(Request $request)
 {
    $searchLog = array();
    // searchLog contains the data to be inserted into database 
    $this->dispatch(new SendTicket($searchLog));
 }

It works fine and the data is inserted .
Here, my question is :

  1. How to send the object to the queue ?
  2. What is best way to send data to queue so that we can process ?
Kiran Subedi
  • 2,244
  • 3
  • 17
  • 34
  • This Laravel behavior was unexpected for so many people, so I'm glad to see that there is a related bug report here: https://github.com/laravel/framework/issues/14526 – Ryan Oct 31 '17 at 19:57

3 Answers3

23

The problem is in the use Illuminate\Queue\SerializesModels;, which tries to serialize the SearchLog $log param which you're passing to the constructor. Since your model is not saved yet, it doesn't have the identifier.

According to Laravel documentation:

If your queued job accepts an Eloquent model in its constructor, only the identifier for the model will be serialized onto the queue. When the job is actually handled, the queue system will automatically re-retrieve the full model instance from the database.

The workaround would be to remove SerializesModels trait from the Job class you're willing to save your model in.

Ronen
  • 734
  • 1
  • 9
  • 14
  • https://stackoverflow.com/a/42981667/470749 is a related question that helped me. – Ryan Oct 31 '17 at 19:56
  • @Ryan Hi Ryan, please help me understand this "only the identifier for the model will be serialized". Its still unclear to me. Even I am passing a model instance to the Job constructor. Although, it works fine for most of the time. Sometimes it throws "No query results for model". I believe solution to my problem lies somewhere around what you have stated. – Aman Aug 03 '18 at 13:03
  • @ronen thanks for pointing this out. had the same issue. my query has a group by and that did not include a primary key so i had to select only the foreign keys (group by foreign key) and ran into this issue. i removed the serialize in the mail class and bam! it works. – w1n78 Nov 04 '19 at 22:06
  • @Ronen Tried to remove ```SerializesModels``` trait and it worked fine. But according to your quote in document, I realized that when I get data from database, I hadn't get ```id``` field to result. Thus, I added ```id``` to ```Eloquent``` object and it worked too. – simpsons3 Dec 14 '20 at 02:32
  • Yes, the "identifier for the model" is what getting stored. By default Laravel uses an $id field as a primary key for the model. Even though you can override it. Sometimes people like to use uuid instead. You can read more about it here: https://laravel.com/docs/eloquent#primary-keys – Ronen Feb 13 '21 at 13:50
4

I ran into the same issue.

It seems if you want to push an Model to the queue only its ID will be saved in the payload. So if you haven't saved the Model yet, it wont be available in the handler.

After all I found it in the documentation in the section Queues and Eloquent Models.

To solve this issue I see two solutions, the first is to make sure you have a persistent Model:

public function store(Request $request)
{
 $searchLog = array();
 // searchLog contains the data to be inserted into database 
 $log = new SearchLog();
 //Save the Searchlog beforehand if it doesn't have any data constraints
 $log->save();
 //Dispatch the Job with the saved Model
 $this->dispatch(new SendTicket($log , $searchLog));
 }

or put the full Model Saving process to the handler only, like you did in your example.

//Full saving/initializing is happening here
public function handle()
{
  SearchLog::create($this->searchLog);   
}

In my case I had to save the Model to a database in a high performance process, so i put it fully in the handler that my process wasn't dependent on the db saving speed. So i would put it in the handle() function.

Florian Bauer
  • 626
  • 3
  • 12
2

This issue is usually raised if the Model is not saved or persisted yet. Check your model instance and persistance. Another thing may raise this issue is Multi-Tenancy. So if you are using or building a Multi Tenant application with Multi Databases, you may need to figure out a way to pass the database connection to the queue or just use arrays of data as stated by Tylor Otwell here [5.4] Support queued jobs with unpersisted models

Waiyl Karim
  • 2,810
  • 21
  • 25