Вход Регистрация
Файл: vendor/laravel/framework/src/Illuminate/Queue/Middleware/ThrottlesExceptions.php
Строк: 207
<?php

namespace IlluminateQueueMiddleware;

use 
Closure;
use 
IlluminateCacheRateLimiter;
use 
IlluminateContainerContainer;
use 
Throwable;

class 
ThrottlesExceptions
{
    
/**
     * The developer specified key that the rate limiter should use.
     *
     * @var string
     */
    
protected $key;

    
/**
     * Indicates whether the throttle key should use the job's UUID.
     *
     * @var bool
     */
    
protected $byJob false;

    
/**
     * The maximum number of attempts allowed before rate limiting applies.
     *
     * @var int
     */
    
protected $maxAttempts;

    
/**
     * The number of seconds until the maximum attempts are reset.
     *
     * @var int
     */
    
protected $decaySeconds;

    
/**
     * The number of minutes to wait before retrying the job after an exception.
     *
     * @var int|(Closure(Throwable): int)
     */
    
protected $retryAfterMinutes 0;

    
/**
     * The callback that determines if the exception should be reported.
     *
     * @var callable
     */
    
protected $reportCallback;

    
/**
     * The callback that determines if rate limiting should apply.
     *
     * @var callable
     */
    
protected $whenCallback;

    
/**
     * The callbacks that determine if the job should be deleted.
     *
     * @var callable[]
     */
    
protected array $deleteWhenCallbacks = [];

    
/**
     * The callbacks that determine if the job should be failed.
     *
     * @var callable[]
     */
    
protected array $failWhenCallbacks = [];

    
/**
     * The prefix of the rate limiter key.
     *
     * @var string
     */
    
protected $prefix 'laravel_throttles_exceptions:';

    
/**
     * The rate limiter instance.
     *
     * @var IlluminateCacheRateLimiter
     */
    
protected $limiter;

    
/**
     * Create a new middleware instance.
     *
     * @param  int  $maxAttempts
     * @param  int  $decaySeconds
     */
    
public function __construct($maxAttempts 10$decaySeconds 600)
    {
        
$this->maxAttempts $maxAttempts;
        
$this->decaySeconds $decaySeconds;
    }

    
/**
     * Process the job.
     *
     * @param  mixed  $job
     * @param  callable  $next
     * @return mixed
     *
     * @throws Throwable
     */
    
public function handle($job$next)
    {
        
$this->limiter Container::getInstance()->make(RateLimiter::class);

        if (
$this->limiter->tooManyAttempts($jobKey $this->getKey($job), $this->maxAttempts)) {
            return 
$job->release($this->getTimeUntilNextRetry($jobKey));
        }

        try {
            
$next($job);

            
$this->limiter->clear($jobKey);
        } catch (
Throwable $throwable) {
            if (
$this->whenCallback && ! call_user_func($this->whenCallback$throwable$this->limiter)) {
                throw 
$throwable;
            }

            if (
$this->reportCallback && call_user_func($this->reportCallback$throwable$this->limiter)) {
                
report($throwable);
            }

            if (
$this->shouldDelete($throwable)) {
                return 
$job->delete();
            }

            if (
$this->shouldFail($throwable)) {
                return 
$job->fail($throwable);
            }

            
$this->limiter->hit($jobKey$this->decaySeconds);

            return 
$job->release($this->getTimeUntilNextRetryAfterException($throwable));
        }
    }

    
/**
     * Specify a callback that should determine if rate limiting behavior should apply.
     *
     * @param  callable  $callback
     * @return $this
     */
    
public function when(callable $callback)
    {
        
$this->whenCallback $callback;

        return 
$this;
    }

    
/**
     * Add a callback that should determine if the job should be deleted.
     *
     * @param  callable|string  $callback
     * @return $this
     */
    
public function deleteWhen(callable|string $callback)
    {
        
$this->deleteWhenCallbacks[] = is_string($callback)
            ? 
fn (Throwable $e) => $e instanceof $callback
            
$callback;

        return 
$this;
    }

    
/**
     * Add a callback that should determine if the job should be failed.
     *
     * @param  callable|string  $callback
     * @return $this
     */
    
public function failWhen(callable|string $callback)
    {
        
$this->failWhenCallbacks[] = is_string($callback)
            ? 
fn (Throwable $e) => $e instanceof $callback
            
$callback;

        return 
$this;
    }

    
/**
     * Run the skip / delete callbacks to determine if the job should be deleted for the given exception.
     *
     * @param  Throwable  $throwable
     * @return bool
     */
    
protected function shouldDelete(Throwable $throwable): bool
    
{
        foreach (
$this->deleteWhenCallbacks as $callback) {
            if (
call_user_func($callback$throwable)) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * Run the skip / fail callbacks to determine if the job should be failed for the given exception.
     *
     * @param  Throwable  $throwable
     * @return bool
     */
    
protected function shouldFail(Throwable $throwable): bool
    
{
        foreach (
$this->failWhenCallbacks as $callback) {
            if (
call_user_func($callback$throwable)) {
                return 
true;
            }
        }

        return 
false;
    }

    
/**
     * Set the prefix of the rate limiter key.
     *
     * @param  string  $prefix
     * @return $this
     */
    
public function withPrefix(string $prefix)
    {
        
$this->prefix $prefix;

        return 
$this;
    }

    
/**
     * Specify the number of minutes a job should be delayed when it is released (before it has reached its max exceptions).
     *
     * @param  int|(Closure(Throwable): int)  $backoff
     * @return $this
     */
    
public function backoff($backoff)
    {
        
$this->retryAfterMinutes $backoff;

        return 
$this;
    }

    
/**
     * Get the number of seconds that should elapse before the job is retried after an exception.
     *
     * @param  Throwable  $throwable
     * @return int
     */
    
protected function getTimeUntilNextRetryAfterException(Throwable $throwable)
    {
        
$backoff $this->retryAfterMinutes instanceof Closure
            
call_user_func($this->retryAfterMinutes$throwable)
            : 
$this->retryAfterMinutes;

        return 
$backoff 60;
    }

    
/**
     * Get the cache key associated for the rate limiter.
     *
     * @param  mixed  $job
     * @return string
     */
    
protected function getKey($job)
    {
        if (
$this->key) {
            return 
$this->prefix.$this->key;
        } elseif (
$this->byJob) {
            return 
$this->prefix.$job->job->uuid();
        }

        
$jobName method_exists($job'displayName')
            ? 
$job->displayName()
            : 
get_class($job);

        return 
$this->prefix.hash('xxh128'$jobName);
    }

    
/**
     * Set the value that the rate limiter should be keyed by.
     *
     * @param  string  $key
     * @return $this
     */
    
public function by($key)
    {
        
$this->key $key;

        return 
$this;
    }

    
/**
     * Indicate that the throttle key should use the job's UUID.
     *
     * @return $this
     */
    
public function byJob()
    {
        
$this->byJob true;

        return 
$this;
    }

    
/**
     * Report exceptions and optionally specify a callback that determines if the exception should be reported.
     *
     * @param  callable|null  $callback
     * @return $this
     */
    
public function report(?callable $callback null)
    {
        
$this->reportCallback $callback ?? fn () => true;

        return 
$this;
    }

    
/**
     * Get the number of seconds that should elapse before the job is retried.
     *
     * @param  string  $key
     * @return int
     */
    
protected function getTimeUntilNextRetry($key)
    {
        return 
$this->limiter->availableIn($key) + 3;
    }
}
Онлайн: 1
Реклама