HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Jobs/Delay.php
<?php

namespace App\Jobs;

use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Model\Campaign;
use App\Library\Exception\RateLimitExceeded;
use App\Library\Exception\RateLimitReservedByAnotherFileSystem;
use Exception;
use Carbon\Carbon;

use function App\Helpers\with_rate_limits;

class Delay implements ShouldQueue
{
    use Batchable;
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    // @important: set the "retry_after" setting in config/queue.php to a value that is greater than $timeout;
    // Otherse, the job shall be released and attempted again, resulting in error like:
    // "[Job] has been attempted too many times or run too long. The job may have previously timed out."

    // @important: https://laravel.com/docs/8.x/queues#failing-on-timeout
    // Sometimes, IO blocking processes such as sockets or outgoing HTTP connections
    // may not ***RESPECT*** your specified timeout. Therefore, when using these features,
    // you should always attempt to specify a timeout using their APIs as well.
    // For example, when using Guzzle, you should always specify a connection and request timeout value.
    public $timeout = 600;
    public $maxExceptions = 1; // This is required if retryUntil is used, otherwise, the default value is 255
    public $failOnTimeout = true;

    // $tries is no longer needed (or effective) due to the retryUntil() method
    // public $tries = 1;
    protected $wait;
    protected $campaign;
    protected $rateTrackers;
    protected $customer;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($wait, $campaign, array $rateTrackers)
    {
        $this->wait = $wait;
        $this->campaign = $campaign;
        $this->rateTrackers = $rateTrackers;

        $this->customer = $this->campaign->customer;
    }

    /**
     * Determine the time at which the job should timeout.
     *
     * @return \DateTime
     */
    public function retryUntil()
    {
        // @important: remember that messages might be released over and over
        // if there is any limit setting in place
        // As a result, it is just save to have it retry virtually forever
        return now()->addDays(365);
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        if ($this->batch()->cancelled()) {
            return;
        }

        try {
            $this->campaign->logger()->info("Evaluating limit trackers to decide whether or not to resume");

            // Throw Exception here
            with_rate_limits($this->rateTrackers, $this->campaign->getServersPool(), $rateExceededCallback = null, $creditCounted = [], $testMode = true);

            // if everything is okie, then just release this job, remove delay flag
            // The JOB_TYPE_DISPATCH_AND_SEND_MESSAGES batch will trigger the THEN callback and continue
            $this->campaign->setDelayFlag(null);
            $this->campaign->logger()->warning('Evaluation ok, RESUMING Campaign...');

            return;

        } catch (RateLimitExceeded $ex) {

            // Record last activity. Otherwise, this job shall be erase when running "campaign::rerun"
            $this->campaign->debug(function ($info) use ($ex) {
                $info['last_activity_at'] = Carbon::now()->toString();

                // Save delay note
                // @todo: consider making it an interface, rather than access the .delay_note attribute directly like this
                $info['delay_note'] = sprintf($info['last_activity_at'].": delay for %s seconds! %s", $this->wait, $ex->getMessage());

                // Must return;
                return $info;
            });

            $this->campaign->logger()->warning(sprintf("TRY RESUMING BUT rate limits not released! Delay for another %s seconds! %s", $this->wait, $ex->getMessage()));
            $this->release($this->wait);

        } catch (Throwable $ex) {
            $message = sprintf("Something went wrong with Wait job: %s", $ex->getMessage());
            $this->campaign->logger()->error($message);

            throw new Exception($message);
        } finally {
            //
        }
    }
}