fix: Add catch for additional webpush errors (#9662)

Webpush gem throws errors such as `WebPush::ExpiredSubscription`,
`WebPush::InvalidSubscription`, `WebPush::Unauthorized`. We handled only
ExpiredSubscription.

If the SDK threw any other errors, it would pause sending the
notification to all other devices for that user. This change would
update the logic to remove the expired subscription and handle the rest
of the errors gracefully.

Fixes
https://linear.app/chatwoot/issue/CW-3399/webpushinvalidsubscription-host-fcmgoogleapiscom-nethttpnotfound-404
This commit is contained in:
Pranav
2024-06-21 14:58:36 -07:00
committed by GitHub
parent 66c6b8cd4f
commit ee2844877c
3 changed files with 74 additions and 28 deletions

View File

@@ -42,14 +42,12 @@ class Notification::PushNotificationService
app_account_conversation_url(account_id: conversation.account_id, id: conversation.display_id)
end
def send_browser_push?(subscription)
def can_send_browser_push?(subscription)
VapidService.public_key && subscription.browser_push?
end
def send_browser_push(subscription)
return unless send_browser_push?(subscription)
WebPush.payload_send(
def browser_push_payload(subscription)
{
message: JSON.generate(push_message),
endpoint: subscription.subscription_attributes['endpoint'],
p256dh: subscription.subscription_attributes['p256dh'],
@@ -62,11 +60,22 @@ class Notification::PushNotificationService
ssl_timeout: 5,
open_timeout: 5,
read_timeout: 5
)
rescue WebPush::ExpiredSubscription
}
end
def send_browser_push(subscription)
return unless can_send_browser_push?(subscription)
WebPush.payload_send(browser_push_payload(subscription))
Rails.logger.info("Browser push sent to #{user.email} with title #{push_message[:title]}")
rescue WebPush::ExpiredSubscription, WebPush::InvalidSubscription, WebPush::Unauthorized => e
Rails.logger.info "WebPush subscription expired: #{e.message}"
subscription.destroy!
rescue Errno::ECONNRESET, Net::OpenTimeout, Net::ReadTimeout => e
Rails.logger.error "WebPush operation error: #{e.message}"
rescue StandardError => e
ChatwootExceptionTracker.new(e, account: notification.account).capture_exception
true
end
def send_fcm_push(subscription)
@@ -98,7 +107,11 @@ class Notification::PushNotificationService
end
def remove_subscription_if_error(subscription, response)
subscription.destroy! if JSON.parse(response[:body])['results']&.first&.keys&.include?('error')
if JSON.parse(response[:body])['results']&.first&.keys&.include?('error')
subscription.destroy!
else
Rails.logger.info("FCM push sent to #{user.email} with title #{push_message[:title]}")
end
end
def fcm_options(subscription)