Throttle email notifications upon updating document frequently (#4026)

* feat: add needed columns for throttling notifs

* feat: update model

* feat: deliver only one notif in a 12 hour window

* fix: address review comments

* prevent retry if notification update fails
* fix type compatibility instead of circumventing it
* add index for emailedAt

* fix: add metadata attr to EmailProps

* chore: decouple metadata from EmailProps

* chore: add test

* chore: revert sending metadata in props
This commit is contained in:
Apoorv Mishra
2022-09-07 16:51:30 +05:30
committed by GitHub
parent e4023d87e2
commit 1e39b564fe
7 changed files with 264 additions and 17 deletions

View File

@@ -1,3 +1,4 @@
import { subHours } from "date-fns";
import { uniqBy } from "lodash";
import { Op } from "sequelize";
import subscriptionCreator from "@server/commands/subscriptionCreator";
@@ -13,6 +14,7 @@ import {
User,
NotificationSetting,
Subscription,
Notification,
} from "@server/models";
import {
CollectionEvent,
@@ -72,16 +74,26 @@ export default class NotificationsProcessor extends BaseProcessor {
const notify = await this.shouldNotify(document, recipient.user);
if (notify) {
await DocumentNotificationEmail.schedule({
to: recipient.user.email,
eventName:
event.name === "documents.publish" ? "published" : "updated",
const notification = await Notification.create({
event: event.name,
userId: recipient.user.id,
actorId: document.updatedBy.id,
teamId: team.id,
documentId: document.id,
teamUrl: team.url,
actorName: document.updatedBy.name,
collectionName: collection.name,
unsubscribeUrl: recipient.unsubscribeUrl,
});
await DocumentNotificationEmail.schedule(
{
to: recipient.user.email,
eventName:
event.name === "documents.publish" ? "published" : "updated",
documentId: document.id,
teamUrl: team.url,
actorName: document.updatedBy.name,
collectionName: collection.name,
unsubscribeUrl: recipient.unsubscribeUrl,
},
{ notificationId: notification.id }
);
}
}
}
@@ -237,6 +249,23 @@ export default class NotificationsProcessor extends BaseProcessor {
return false;
}
// Deliver only a single notification in a 12 hour window
const notification = await Notification.findOne({
order: [["createdAt", "DESC"]],
where: {
userId: user.id,
documentId: document.id,
emailedAt: {
[Op.not]: null,
[Op.gte]: subHours(new Date(), 12),
},
},
});
if (notification) {
return false;
}
// If this recipient has viewed the document since the last update was made
// then we can avoid sending them a useless notification, yay.
const view = await View.findOne({