From 7aa89f16c9db7cd1ec7a8d68a5afc2ff95b4edc2 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 25 Sep 2022 10:19:44 -0500 Subject: [PATCH] Add:Notification system queueing and queue limit #996 --- client/components/cards/NotificationCard.vue | 15 ++++++++ server/managers/NotificationManager.js | 37 +++++++++++++++++-- .../objects/settings/NotificationSettings.js | 11 +++++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/client/components/cards/NotificationCard.vue b/client/components/cards/NotificationCard.vue index 7f74239e..95ba4852 100644 --- a/client/components/cards/NotificationCard.vue +++ b/client/components/cards/NotificationCard.vue @@ -6,6 +6,7 @@ Fire onTest Event Fire & Fail + Test Enable @@ -52,6 +53,7 @@ export default { } }, methods: { + // For testing using the onTest event fireTestEventAndFail() { this.fireTestEvent(true) }, @@ -74,6 +76,19 @@ export default { this.testing = false }) }, + rapidFireTestEvents() { + this.testing = true + var numFired = 0 + var interval = setInterval(() => { + this.fireTestEvent() + numFired++ + if (numFired > 25) { + this.testing = false + clearInterval(interval) + } + }, 100) + }, + // End testing functions sendTestClick() { const payload = { message: `Trigger this notification with test data?`, diff --git a/server/managers/NotificationManager.js b/server/managers/NotificationManager.js index 60c2599c..cf7a6042 100644 --- a/server/managers/NotificationManager.js +++ b/server/managers/NotificationManager.js @@ -7,7 +7,8 @@ class NotificationManager { this.db = db this.emitter = emitter - this.notificationFailedMap = {} + this.sendingNotification = false + this.notificationQueue = [] } getData() { @@ -35,7 +36,10 @@ class NotificationManager { } async triggerNotification(eventName, eventData, intentionallyFail = false) { - if (!this.db.notificationSettings.isUseable) return false + if (!this.db.notificationSettings.isUseable) return + + // Will queue the notification if sendingNotification and queue is not full + if (!this.checkTriggerNotification(eventName, eventData)) return const notifications = this.db.notificationSettings.getActiveNotificationsForEvent(eventName) for (const notification of notifications) { @@ -44,7 +48,7 @@ class NotificationManager { notification.updateNotificationFired(success) if (!success) { // Failed notification - if (notification.numConsecutiveFailedAttempts > 2) { + if (notification.numConsecutiveFailedAttempts >= this.db.notificationSettings.maxFailedAttempts) { Logger.error(`[NotificationManager] triggerNotification: ${notification.eventName}/${notification.id} reached max failed attempts`) notification.enabled = false } else { @@ -55,9 +59,36 @@ class NotificationManager { await this.db.updateEntity('settings', this.db.notificationSettings) this.emitter('notifications_updated', this.db.notificationSettings) + + this.notificationFinished() + } + + // Return TRUE if notification should be triggered now + checkTriggerNotification(eventName, eventData) { + if (this.sendingNotification) { + if (this.notificationQueue.length >= this.db.notificationSettings.maxNotificationQueue) { + Logger.warn(`[NotificationManager] Notification queue is full - ignoring event ${eventName}`) + } else { + Logger.debug(`[NotificationManager] Queueing notification ${eventName} (Queue size: ${this.notificationQueue.length})`) + this.notificationQueue.push({ eventName, eventData }) + } + return false + } + this.sendingNotification = true return true } + notificationFinished() { + // Delay between events then run next notification in queue + setTimeout(() => { + this.sendingNotification = false + if (this.notificationQueue.length) { // Send next notification in queue + const nextNotificationEvent = this.notificationQueue.shift() + this.triggerNotification(nextNotificationEvent.eventName, nextNotificationEvent.eventData) + } + }, this.db.notificationSettings.notificationDelay) + } + sendTestNotification(notification) { const eventData = notificationData.events.find(e => e.name === notification.eventName) if (!eventData) { diff --git a/server/objects/settings/NotificationSettings.js b/server/objects/settings/NotificationSettings.js index 27bb1180..838256f6 100644 --- a/server/objects/settings/NotificationSettings.js +++ b/server/objects/settings/NotificationSettings.js @@ -7,6 +7,9 @@ class NotificationSettings { this.appriseType = 'api' this.appriseApiUrl = null this.notifications = [] + this.maxFailedAttempts = 5 + this.maxNotificationQueue = 20 // once reached events will be ignored + this.notificationDelay = 1000 // ms delay between firing notifications if (settings) { this.construct(settings) @@ -17,6 +20,9 @@ class NotificationSettings { this.appriseType = settings.appriseType this.appriseApiUrl = settings.appriseApiUrl || null this.notifications = (settings.notifications || []).map(n => new Notification(n)) + this.maxFailedAttempts = settings.maxFailedAttempts || 5 + this.maxNotificationQueue = settings.maxNotificationQueue || 20 + this.notificationDelay = settings.notificationDelay || 1000 } toJSON() { @@ -24,7 +30,10 @@ class NotificationSettings { id: this.id, appriseType: this.appriseType, appriseApiUrl: this.appriseApiUrl, - notifications: this.notifications.map(n => n.toJSON()) + notifications: this.notifications.map(n => n.toJSON()), + maxFailedAttempts: this.maxFailedAttempts, + maxNotificationQueue: this.maxNotificationQueue, + notificationDelay: this.notificationDelay } }