Skip to content

Dashboard

Laravel job is retried even when option tries is set to 1

Created by Admin

Lỗi như tiêu đề, bạn có thể xem tại https://github.com/laravel/framework/issues/15696 Và 1 lần nữa mấy anh contributors của laravel lại bảo đây là feature =)) https://github.com/laravel/framework/issues/15696#issuecomment-250935907

Tóm tắt lại là laravel sẽ chạy lại job sau khi job bị timeout bất kể bạn để try time bao nhiêu lần. Đọc code của laravel bạn sẽ thấy. Illuminate\Queue\Worker::markJobAsFailedIfAlreadyExceedsMaxAttempts

    /**
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
     *
     * This will likely be because the job previously exceeded a timeout.
     *
     * @param  string  $connectionName
     * @param  \Illuminate\Contracts\Queue\Job  $job
     * @param  int  $maxTries
     * @return void
     */
    protected function markJobAsFailedIfAlreadyExceedsMaxAttempts($connectionName, $job, $maxTries)
    {
        $maxTries = ! is_null($job->maxTries()) ? $job->maxTries() : $maxTries;

        $timeoutAt = $job->timeoutAt();

        if ($timeoutAt && Carbon::now()->getTimestamp() <= $timeoutAt) {
            return;
        }

        if (! $timeoutAt && ($maxTries === 0 || $job->attempts() <= $maxTries)) {
            return;
        }

        $this->failJob($connectionName, $job, $e = new MaxAttemptsExceededException(
            $job->resolveName().' has been attempted too many times or run too long. The job may have previously timed out.'
        ));

        throw $e;
    }

Cách fix:

1. Set option retry_after và restart queue mỗi 1 khoảng thời gian < retry_after time

Ví dụ: Bạn set job retry_after bằng 3600 s và restart queue mỗi 2000s.

2. Chia nhỏ job thằng nhiều job con.

Nếu job của bạn đang thực hiện 1 công việc có thể chia nhỏ hơn, hay tạo ra job con và dispatch các job con trong job cha để tránh timeout.

3. Tạo 1 class extends từ class Illuminate\Queue\Worker và ghi đè funtion markJobAsFailedIfAlreadyExceedsMaxAttempts

Đơn giản là xóa 3 cái dòng của nợ kia đi.

    /**
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
     *
     * This will likely be because the job previously exceeded a timeout.
     *
     * @param  string  $connectionName
     * @param  \Illuminate\Contracts\Queue\Job  $job
     * @param  int  $maxTries
     * @return void
     */
    protected function markJobAsFailedIfAlreadyExceedsMaxAttempts($connectionName, $job, $maxTries)
    {
        $maxTries = ! is_null($job->maxTries()) ? $job->maxTries() : $maxTries;

        $timeoutAt = $job->timeoutAt();

        // if ($timeoutAt && Carbon::now()->getTimestamp() <= $timeoutAt) {
        //    return;
        // }

        if (! $timeoutAt && ($maxTries === 0 || $job->attempts() <= $maxTries)) {
            return;
        }

        $this->failJob($connectionName, $job, $e = new MaxAttemptsExceededException(
            $job->resolveName().' has been attempted too many times or run too long. The job may have previously timed out.'
        ));

        throw $e;
    }

Và đừng quên viết 1 console lệnh cho class worker mới nhé. Tham khảo code ở file vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php Bạn nào viết xong chia sẻ lại cho mình nhé, mình chưa viết =))

Source: https://viblo.asia/p/laravel-job-is-retried-even-when-option-tries-is-set-to-1-gDVK2BnwKLj