From 34892aff6f313653d87f08659927b3170a744b38 Mon Sep 17 00:00:00 2001 From: fs Date: Mon, 6 Apr 2026 12:29:04 +0200 Subject: [PATCH] fix(notifications): use per-type dedup window, 24h for scheduler failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change DEDUPE_TYPES from bool to int|true — int value overrides the default 30-min window. scheduler.job_failed uses 1440 min (24h) so admins receive at most one notification per failed job per day. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Module/Notifications/Service/NotificationService.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/notifications/lib/Module/Notifications/Service/NotificationService.php b/modules/notifications/lib/Module/Notifications/Service/NotificationService.php index be8abc2..216107f 100644 --- a/modules/notifications/lib/Module/Notifications/Service/NotificationService.php +++ b/modules/notifications/lib/Module/Notifications/Service/NotificationService.php @@ -9,13 +9,15 @@ class NotificationService { private const MESSAGE_META_KEY = '__message'; private const DEDUPE_WINDOW_MINUTES = 30; + + /** @var array Type → dedup window in minutes (true = default window). */ private const DEDUPE_TYPES = [ 'user.created' => true, 'user.deleted' => true, 'user.activated' => true, 'user.deactivated' => true, 'user.assignment_changed' => true, - 'scheduler.job_failed' => true, + 'scheduler.job_failed' => 1440, ]; public function __construct( @@ -233,6 +235,9 @@ class NotificationService return []; } + $windowMinutes = self::DEDUPE_TYPES[$type]; + $windowMinutes = is_int($windowMinutes) && $windowMinutes > 0 ? $windowMinutes : self::DEDUPE_WINDOW_MINUTES; + $tenantScope = $tenantId !== null && $tenantId > 0 ? $tenantId : 0; $raw = implode('|', [ 'recipient:' . $recipientUserId, @@ -243,7 +248,7 @@ class NotificationService return [ 'fingerprint' => hash('sha256', $raw), - 'bucket' => intdiv(time(), self::DEDUPE_WINDOW_MINUTES * 60), + 'bucket' => intdiv(time(), $windowMinutes * 60), ]; }