Skip to content

Commit 552bdee

Browse files
JaZotaylorotwell
andauthored
[11.x] Add option to report throttled exception in ThrottlesExceptions middleware (#50896)
* feat: add option to report the throttled exception * Update ThrottlesExceptions.php --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 627e9c5 commit 552bdee

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

src/Illuminate/Queue/Middleware/ThrottlesExceptions.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ class ThrottlesExceptions
4343
*/
4444
protected $retryAfterMinutes = 0;
4545

46+
/**
47+
* The callback that determines if the exception should be reported.
48+
*
49+
* @var callable
50+
*/
51+
protected $reportCallback;
52+
4653
/**
4754
* The callback that determines if rate limiting should apply.
4855
*
@@ -101,6 +108,10 @@ public function handle($job, $next)
101108
throw $throwable;
102109
}
103110

111+
if ($this->reportCallback && call_user_func($this->reportCallback, $throwable)) {
112+
report($throwable);
113+
}
114+
104115
$this->limiter->hit($jobKey, $this->decaySeconds);
105116

106117
return $job->release($this->retryAfterMinutes * 60);
@@ -188,6 +199,19 @@ public function byJob()
188199
return $this;
189200
}
190201

202+
/**
203+
* Report exceptions and optionally specify a callback that determines if the exception should be reported.
204+
*
205+
* @param callable|null $callback
206+
* @return $this
207+
*/
208+
public function report(?callable $callback = null)
209+
{
210+
$this->reportCallback = $callback ?? fn () => true;
211+
212+
return $this;
213+
}
214+
191215
/**
192216
* Get the number of seconds that should elapse before the job is retried.
193217
*

src/Illuminate/Queue/Middleware/ThrottlesExceptionsWithRedis.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public function handle($job, $next)
5454
throw $throwable;
5555
}
5656

57+
if ($this->reportCallback && call_user_func($this->reportCallback, $throwable)) {
58+
report($throwable);
59+
}
60+
5761
$this->limiter->acquire();
5862

5963
return $job->release($this->retryAfterMinutes * 60);

tests/Integration/Queue/ThrottlesExceptionsTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Exception;
66
use Illuminate\Bus\Dispatcher;
77
use Illuminate\Bus\Queueable;
8+
use Illuminate\Contracts\Debug\ExceptionHandler;
89
use Illuminate\Contracts\Queue\Job;
910
use Illuminate\Queue\CallQueuedHandler;
1011
use Illuminate\Queue\InteractsWithQueue;
@@ -262,6 +263,36 @@ public function release()
262263
$this->assertTrue($job->released);
263264
$this->assertTrue($job->handled);
264265
}
266+
267+
public function testReportingExceptions()
268+
{
269+
$this->spy(ExceptionHandler::class)
270+
->shouldReceive('report')
271+
->twice()
272+
->with(m::type(RuntimeException::class));
273+
274+
$job = new class
275+
{
276+
public function release()
277+
{
278+
return $this;
279+
}
280+
};
281+
$next = function () {
282+
throw new RuntimeException('Whoops!');
283+
};
284+
285+
$middleware = new ThrottlesExceptions();
286+
287+
$middleware->report();
288+
$middleware->handle($job, $next);
289+
290+
$middleware->report(fn () => true);
291+
$middleware->handle($job, $next);
292+
293+
$middleware->report(fn () => false);
294+
$middleware->handle($job, $next);
295+
}
265296
}
266297

267298
class CircuitBreakerTestJob

tests/Integration/Queue/ThrottlesExceptionsWithRedisTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Exception;
66
use Illuminate\Bus\Dispatcher;
77
use Illuminate\Bus\Queueable;
8+
use Illuminate\Contracts\Debug\ExceptionHandler;
89
use Illuminate\Contracts\Queue\Job;
910
use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis;
1011
use Illuminate\Queue\CallQueuedHandler;
@@ -14,6 +15,7 @@
1415
use Illuminate\Support\Str;
1516
use Mockery as m;
1617
use Orchestra\Testbench\TestCase;
18+
use RuntimeException;
1719

1820
class ThrottlesExceptionsWithRedisTest extends TestCase
1921
{
@@ -116,6 +118,36 @@ protected function assertJobRanSuccessfully($class, $key)
116118

117119
$this->assertTrue($class::$handled);
118120
}
121+
122+
public function testReportingExceptions()
123+
{
124+
$this->spy(ExceptionHandler::class)
125+
->shouldReceive('report')
126+
->twice()
127+
->with(m::type(RuntimeException::class));
128+
129+
$job = new class
130+
{
131+
public function release()
132+
{
133+
return $this;
134+
}
135+
};
136+
$next = function () {
137+
throw new RuntimeException('Whoops!');
138+
};
139+
140+
$middleware = new ThrottlesExceptionsWithRedis();
141+
142+
$middleware->report();
143+
$middleware->handle($job, $next);
144+
145+
$middleware->report(fn () => true);
146+
$middleware->handle($job, $next);
147+
148+
$middleware->report(fn () => false);
149+
$middleware->handle($job, $next);
150+
}
119151
}
120152

121153
class CircuitBreakerWithRedisTestJob

0 commit comments

Comments
 (0)