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:
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user