Skip to content

Commit

Permalink
[11.x] Add option to report throttled exception in ThrottlesException…
Browse files Browse the repository at this point in the history
…s middleware (#50896)

* feat: add option to report the throttled exception

* Update ThrottlesExceptions.php

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
JaZo and taylorotwell authored Apr 3, 2024
1 parent 627e9c5 commit 552bdee
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/Illuminate/Queue/Middleware/ThrottlesExceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ class ThrottlesExceptions
*/
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.
*
Expand Down Expand Up @@ -101,6 +108,10 @@ public function handle($job, $next)
throw $throwable;
}

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

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

return $job->release($this->retryAfterMinutes * 60);
Expand Down Expand Up @@ -188,6 +199,19 @@ public function byJob()
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public function handle($job, $next)
throw $throwable;
}

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

$this->limiter->acquire();

return $job->release($this->retryAfterMinutes * 60);
Expand Down
31 changes: 31 additions & 0 deletions tests/Integration/Queue/ThrottlesExceptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use Illuminate\Bus\Dispatcher;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Queue\CallQueuedHandler;
use Illuminate\Queue\InteractsWithQueue;
Expand Down Expand Up @@ -262,6 +263,36 @@ public function release()
$this->assertTrue($job->released);
$this->assertTrue($job->handled);
}

public function testReportingExceptions()
{
$this->spy(ExceptionHandler::class)
->shouldReceive('report')
->twice()
->with(m::type(RuntimeException::class));

$job = new class
{
public function release()
{
return $this;
}
};
$next = function () {
throw new RuntimeException('Whoops!');
};

$middleware = new ThrottlesExceptions();

$middleware->report();
$middleware->handle($job, $next);

$middleware->report(fn () => true);
$middleware->handle($job, $next);

$middleware->report(fn () => false);
$middleware->handle($job, $next);
}
}

class CircuitBreakerTestJob
Expand Down
32 changes: 32 additions & 0 deletions tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use Illuminate\Bus\Dispatcher;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis;
use Illuminate\Queue\CallQueuedHandler;
Expand All @@ -14,6 +15,7 @@
use Illuminate\Support\Str;
use Mockery as m;
use Orchestra\Testbench\TestCase;
use RuntimeException;

class ThrottlesExceptionsWithRedisTest extends TestCase
{
Expand Down Expand Up @@ -116,6 +118,36 @@ protected function assertJobRanSuccessfully($class, $key)

$this->assertTrue($class::$handled);
}

public function testReportingExceptions()
{
$this->spy(ExceptionHandler::class)
->shouldReceive('report')
->twice()
->with(m::type(RuntimeException::class));

$job = new class
{
public function release()
{
return $this;
}
};
$next = function () {
throw new RuntimeException('Whoops!');
};

$middleware = new ThrottlesExceptionsWithRedis();

$middleware->report();
$middleware->handle($job, $next);

$middleware->report(fn () => true);
$middleware->handle($job, $next);

$middleware->report(fn () => false);
$middleware->handle($job, $next);
}
}

class CircuitBreakerWithRedisTestJob
Expand Down

0 comments on commit 552bdee

Please sign in to comment.