Created
July 31, 2018 16:02
-
-
Save scottwakefield/81da8c00e63101a20fe6ea3735c21f02 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Notifications; | |
use Illuminate\Support\Str; | |
use Illuminate\Cache\RateLimiter; | |
use Illuminate\Support\Facades\Log; | |
use Illuminate\Notifications\RoutesNotifications; | |
trait RoutesThrottledNotifications | |
{ | |
// Include the original trait, but map the notify method to another name... | |
use RoutesNotifications { | |
RoutesNotifications::notify as parentNotify; | |
} | |
// Our customised method... | |
public function notify($instance) | |
{ | |
// Here we check whether the Notification is an instance of a new | |
// ThrottledNotification interface. The interface itself ensures | |
// that certain methods are available on the notification. | |
if ($instance instanceof ThrottledNotification) { | |
// Get the throttle key for the given Notification. | |
$key = $this->throttleKey($instance); | |
// Use the key to check whether there have been too many attempts... | |
if ($this->limiter()->tooManyAttempts($key, $this->maxAttempts())) { | |
// It's up to you what you do here. We're logging the skipped | |
// notifications. | |
return Log::notice("Skipping sending notification with key `$key`. Rate limit reached."); | |
} | |
// The attempt was OK, so we increment the limiter, passing through | |
// the decay minutes that the ThrottledNotification interface | |
// demands to be set the Notification that implements it. | |
$this->limiter()->hit($key, $instance->throttleDecayMinutes()); | |
} | |
// Execute the original notify() method. | |
$this->parentNotify($instance); | |
} | |
/** | |
* Get the rate limiter instance. | |
*/ | |
protected function limiter() | |
{ | |
return app(RateLimiter::class); | |
} | |
/** | |
* Build the notification throttle key from the Notification class name, | |
* the Notification's throttle key id and the current users id. | |
* | |
* Output example: productupdated|1|10 | |
*/ | |
protected function throttleKey($instance) | |
{ | |
return Str::lower( | |
class_basename($instance) . '|' . $instance->throttleKeyId() . '|' . $this->getAuthIdentifier() | |
); | |
} | |
/** | |
* Set the max attempts to 1. | |
*/ | |
protected function maxAttempts() | |
{ | |
return 1; | |
} | |
} |
\Illuminate\Cache\RateLimiter::hit()
takes seconds, not minutes, as the second parameter.
And your article is missing an implementation for \App\Notifications\ThrottledNotification
. Easy enough to figure out, but wouldn't hurt to add it.
Hi @miken32
Thanks for the comment 👍
When the article was written, \Illuminate\Cache\RateLimiter::hit()
did take minutes, but I can see that was changed to take seconds in January. I'll be sure to add a note to the article along with an example implementation of \App\Notifications\ThrottledNotification
.
Thanks again for the heads up!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello there,
Following: https://clubstudio.co.uk/journal/rate-limiting-notifications-in-laravel I'm trying to implement this, but I seems to be msising a few things.
Do I change my notification as followed:
class UserFollowed extends ThrottledNotification implements ShouldQueue
-> This was originally =class UserFollowed extends Notification implements ShouldQueue
Also, the method unreadNotifcations() seems to break:
https://i.gyazo.com/1741e68d43adcd0ee069bfdc0d87a615.png
Is this something I can take care of, or doesn't this work this way?