This post is from the professional Laravel developer community, original link: learnku.com/laravel/t/3…

When you create queue jobs, listeners, or subscribers to push to the queue, you may begin to think that once dispatched, it’s entirely up to you for the queue worker to decide what to do with your logic.

HMM… That’s not to say you can’t interact with the queue worker from within the job, but usually if you do, it’s not necessary.

The magic SAO operation comes from the trait “InteractsWithQueue.” . While the queued job is being pulled from the queue, this [CallQueuedListener] (HTTP: / / https://github.com/laravel/framework/blob/5.8/src/Illuminate/Events/CallQueuedListener.php#L90-L104 ) checks to see if it is using the InteractsWithQueue trait, and if so, the framework injects the underlying instance of “queue Jobs” internally.

This “task” instance is similar to a driver that wraps the real Job class, containing information such as queue connections and attempts.


background

I’ll take a transcoding Job as an example. This is a task to convert broadcast audio files to 192kbps MP3 format. Because this is set up in a free transcoding queue, its usefulness is limited.


Check the number of attempts

Attempts () is the first method invoked and, as the name suggests, returns the number of attempts, a queue job is always started with an Attempt.

This method is intended to be used in conjunction with other methods… , like fail() or release() (delay). For illustrative purposes, we will notify the user of the number of retries: each time we try to convert in an idle queue (conversion code), we will notify the user of the number of retries we are in, giving him the option to cancel future conversions (conversion code).

<? php namespace App\Jobs; use App\Podcast; use Transcoder\Transcoder; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use App\Notifications\PodcastTranscoded; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Foundation\Bus\Dispatchable; use App\Notifications\RetyingPodcastTranscode; class TranscodePodcast { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Transcoder Instance * * @var \App\Podcast */ protected$podcast; /** * Create a new transcoding podcast instance. * * @param \App\Podcast$podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast; } /** * execute queue job. ** @param \Transcoder\Transcoder$podcast
     * @return void
     */
    public function handle(Transcoder $transcoder) {// tell the user how many retries we haveif ($this->attempts() > 1) {
            $this->podcast->publisher->notify(new RetryingPodcastTranscode($this->podcast, $this->attempts());
        }
        $transcoded = $this->transcoder->setFile($event->podcast)
            ->format('mp3') ->bitrate(192) ->start(); // Associate the transcoding podcast with the original podcast$this->podcast->transcode()->associate($transcoded); // Notify the publisher of the podcast that his podcast is ready$this->publisher->notify(new PodcastTranscoded($this->podcast)); }}Copy the code

Telling the user how many times we’re going to retry something is useful when the logic fails in advance, allowing the user (or developer) to check what went wrong, but of course you can do more.

Personally, I like to do this after “Job” fails, and if there is a retry time, tell him that we will try again later. Of course, this is just an example.


Example Delete a Job queue

The second method is delete(). As you might guess, you can delete the current “queue Job” from the queue. This comes in handy when the queue Job or listener should not be processed after being queued for a variety of reasons. For example, consider the scenario where the publisher that uploaded the podcast is deactivated for any reason (such as a TOS conflict) before transcoding occurs, and we should not process the podcast.

We will add this code in the previous example:

<? php namespace App\Jobs; use App\Podcast; use Transcoder\Transcoder; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use App\Notifications\PodcastTranscoded; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Foundation\Bus\Dispatchable; use App\Notifications\RetyingPodcastTranscode; class TranscodePodcast { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Transcoder Instance * * @var \App\Podcast */ protected$podcast; /** * Create a new transcoding podcast instance. * * @param \App\Podcast$podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast; } /** * execute queue job. ** @param \Transcoder\Transcoder$podcast
     * @return void
     */
    public function handle(Transcoder $transcoder) {// If the publisher is disabled, delete this queue jobif ($this->podcast->publisher->isDeactivated()) {
            $this->delete(); } // Tell the user how many retries we haveif ($this->attempts() > 1) {
            $this->podcast->publisher->notify(new RetryingPodcastTranscode($this->podcast, $this->attempts());
        }
        $transcoded = $this->transcoder->setFile($event->podcast)
            ->format('mp3') ->bitrate(192) ->start(); // Associate the transcoding podcast with the original podcast$this->podcast->transcode()->associate($transcoded); // Notify the publisher of the podcast that his podcast is ready$this->publisher->notify(new PodcastTranscoded($this->podcast)); }}Copy the code

If you need to delete a job on a model that might have been deleted, You may need to set [$deleteWhenMissingModels] (https://laravel.com/docs/5.8/queues#ignoring-missing-models) is true t avoid processing does not exist.


Failed queue Job. Procedure

This is very, very handy when you need to control tamper with logic, because using an empty “return” statement marks “Job” as successfully completed. You can force queued jobs to fail in the hope of an exception, allowing the handler to retry later if possible.

This gives you more control when a job fails in any case, or you can use the “failed ()” method, which allows you to perform any cleaning manipulation after a failure, such as notifying the user or deleting something.

In this example, if the podcast cannot be retrieved from the store for any reason (such as when the CDN is down), the job will fail and a custom exception will be thrown.

<? php namespace App\Jobs; use App\Podcast; use Transcoder\Transcoder; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use App\Exceptions\PodcastUnretrievable; use App\Notifications\PodcastTranscoded; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Foundation\Bus\Dispatchable; use App\Notifications\RetyingPodcastTranscode; class TranscodePodcast { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * transcoder instance ** @var.app/Podcast */ protected$podcast; /** * Create a new transcoding Podcast instance. * * @param \App\Podcast$podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast; } /** * execute queue job. ** @param \Transcoder\Transcoder$podcast
     * @return void
     */
    public function handle(Transcoder $transcoder) {// If the publisher is disabled, delete this queue jobif ($this->podcast->publisher->isDeactivated()) {
            $this->delete(); } // If the podcast cannot be retrieved from the storage, we will fail.if ($this->podcast->fileDoesntExists()) {
            $this->fail(new PodcastUnretrievable($this->podcast)); } // Tell the user how many retries we haveif ($this->attempts() > 1) {
            $this->podcast->publisher->notify(new RetryingPodcastTranscode($this->podcast, $this->attempts());
        }
        
        $transcoded = $this->transcoder->setFile($event->podcast)
                ->format('mp3') ->bitrate(192) ->start(); // Associate the transcoding podcast with the original podcast$this->podcast->transcode()->associate($transcoded); // Notify the publisher of the podcast that his podcast is ready$this->publisher->notify(new PodcastTranscoded($this->podcast)); }}Copy the code

Now, to the final method.


Release (delay) the queue Job

This is probably the most useful method for trait traits, as it allows you to push this queue job further in the future. This method is used to limit the rate of queue jobs.

In addition to rate limits, you can use it in situations where it’s not available but you want to use it in the near future while avoiding pre-emptive failure.

In the last example, we will delay transcoding for later use: if the transcoder is in heavy use, we will delay transcoding for 5 minutes until the load drops.

<? php namespace App\Jobs; use App\Podcast; use Transcoder\Transcoder; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use App\Exceptions\PodcastUnretrievable; use App\Notifications\PodcastTranscoded; use Illuminate\Queue\InteractsWithQueue; use App\Notifications\TranscoderHighUsage; use Illuminate\Foundation\Bus\Dispatchable; use App\Notifications\RetyingPodcastTranscode; class TranscodePodcast { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Transcoder Instance * * @var \App\Podcast */ protected$podcast; /** * Create a new transcoding podcast instance. * * @param \App\Podcast$podcast
     * @return void
     */
    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast; } /** * execute queue job. ** @param \Transcoder\Transcoder$podcast
     * @return void
     */
    public function handle(Transcoder $transcoder) {// If the publisher is disabled, delete this queue jobif ($this->podcast->publisher->isDeactivated()) {
            $this->delete(); } // If the podcast cannot be retrieved from the storage, we will fail.if ($this->podcast->fileDoesntExists()) {
            $this->fail(new PodcastUnretrievable($this->podcast)); } // If the transcoder usage is high, we will // t delay transcoding 5 minutes. Otherwise we run the risk of delaying the transcoder process // it will record all transcoding subprocesses.if ($transcoder->getLoad()->isHigh()) {
            $delay = 60 * 5;
            $this->podcast->publisher->notify(new TranscoderHighUsage($this->podcast, $delay));
            $this->release($delay); } // Tell the user how many retries we haveif ($this->attempts() > 1) {
            $this->podcast->publisher->notify(new RetryingPodcastTranscode($this->podcast, $this->attempts());
        }
        
        $transcoded = $this->transcoder->setFile($event->podcast)
                ->format('mp3') ->bitrate(192) ->start(); // Associate the transcoding podcast with the original podcast$this->podcast->transcode()->associate($transcoded); // Notify the publisher of the podcast that his podcast is ready$this->publisher->notify(new PodcastTranscoded($this->podcast)); }}Copy the code

Special methods can be used, for example, to obtain some timeslots allocated to the transcoder, and to delay the job if the timeslot of the transcoder is full. There’s only so much you can do in a queuing job. Enjoy the line.