Search code examples
laravelpush-notificationonesignallaravel-notificationlaravel-scheduler

Laravel schedule push notification and cancel it if necessary


In my app with Laravel on back-end users can send messages to each other.

I want to send push notification to app users on new inbox message, but I need to send messages only if user hadn't already read this message.

So I see it that way

  1. On every message sended I need to schedule Laravel notification after 1 minute
  2. if user already received this message I need to cancel this notification

How can dismiss scheduled notification in Laravel? Is this approach fine and actual now?

Class extends Notification

public function via($notifiable)
{
    if($this->dontSend($notifiable)) {
        return [];
    }
    return ['mail'];
}

public function dontSend($notifiable)
{
    return $this->appointment->status === 'cancelled';
} 

Maybe there is more convenient way to handle it? For example, to send push every time but somehow dismiss it showing from app if it's already launched?


Solution

  • One way to do it would be something like this;

    • Before you trigger your notification create a unique identifier(sha1 could be an option) with the combination of user_id. Let's say it is SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C. Send it to the notification. Both notification and message will be send at the same time, but notification will have one minute delay.
    $identifier = Str::random(64);
    $delay = now()->addMinute();
    $user->notify((new MyNotification($identifier))->delay($delay));
    // send a request that contains identifier.
    
    • You set this to the Redis with TTL of 2 minutes. It will be gone if there is no action.
    Redis::set('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C', 1, 120);
    
    • While sending a message to the user, attach this identifier to the message. When user read that message, you make a request to your /read endpoint with all the parameters + the identifier.
    • When you receive the request, delete the key from Redis. (user received the message)
    Redis::del('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
    
    • In your Notification class, implement a small method to check whether the key exists in Redis.
    Redis::exists('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
    
    class MyNotification extends BaseNotification
    {
        use Queueable;
    
        private $identifier;
    
        public function __construct($identifier)
        {
            $this->identifier = $identifier;
        }
    
        public function via()
        {
            return $this->isValid() ? ['mail'] : [];
        }
    
        public function isValid()
        {
            return Redis::exists($this->identifier);
        }
    
        public function toMail()
        {
            // details..
        }
    }
    

    It doesn't have to be Redis but it is a perfect match for these kind of key/value structure.