Fix Telegram notification spam with channel-level rate limiting (#951)
* Fix Telegram notification spam with channel-level rate limiting
Addresses issue #950 where Telegram notifications were sent excessively
(96-288 messages per day per task) due to the delete-and-recreate pattern
added in commit 105a913a to fix navbar notification pile-up.
Changes:
- Add channel_sent_at JSON field to notifications table to track when
each channel (telegram, email, push) was last sent
- Add helper methods to notification model:
- markChannelAsSent(channel): Records send timestamp
- wasChannelRecentlySent(channel, threshold): Checks if sent within 24h
- Modify sendTelegramNotification() to check rate limit before sending
- Update service layer (dueTaskService, deferredTaskService,
dueProjectService) to preserve channel_sent_at when recreating
notifications
- Add comprehensive unit and integration tests (20 tests, all passing)
Impact:
- Reduces Telegram notifications from 96-288/day to 1/day per item
- Preserves in-app notification refresh behavior (every 5-15 min)
- Maintains navbar pile-up fix from original commit
- Rate limit configurable (default: 24 hours)
Fixes #950
* Fix linting and formatting issues
* Fix integration test that was trying to access private function
* Fix prettier formatting in integration test
This commit is contained in:
parent
471d29e495
commit
11cd77bedd
8 changed files with 739 additions and 2 deletions
|
|
@ -67,6 +67,9 @@ async function checkDeferredTasks() {
|
|||
notif.data?.reason === 'defer_until_reached'
|
||||
);
|
||||
|
||||
// Preserve channel_sent_at for rate limiting when recreating notifications
|
||||
let preservedChannelSentAt = null;
|
||||
|
||||
if (existingNotification) {
|
||||
// If notification was dismissed, don't create it again
|
||||
if (existingNotification.dismissed_at) {
|
||||
|
|
@ -76,6 +79,9 @@ async function checkDeferredTasks() {
|
|||
// If notification is unread, delete it before creating the new one
|
||||
// This prevents duplicate notifications from piling up
|
||||
if (!existingNotification.read_at) {
|
||||
// Preserve channel_sent_at to maintain rate limiting across recreations
|
||||
preservedChannelSentAt =
|
||||
existingNotification.channel_sent_at;
|
||||
await existingNotification.destroy();
|
||||
} else {
|
||||
// If it was already read, skip creating a new one
|
||||
|
|
@ -101,6 +107,7 @@ async function checkDeferredTasks() {
|
|||
reason: 'defer_until_reached',
|
||||
},
|
||||
sentAt: new Date(),
|
||||
channel_sent_at: preservedChannelSentAt,
|
||||
});
|
||||
|
||||
notificationsCreated++;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue