A reactive-pipeline fix in one of the most-starred projects in this series.
respuesta corta
In Halo, a subscriber with several notifiers enabled, such as email plus a plugin notifier, got one duplicate in-app notification per notifier. The fix collects the prepared notification elements, sends one through each notifier, and creates a single in-app notification. It was merged as PR #10264 and closed issue #7747.
The problem
Halo is an open-source website builder and CMS written in Java. Issue #7747, reported on Halo 2.21.7, showed duplicate notification messages once more than one notifier was installed.
Root cause
DefaultNotificationCenter.dispatchNotification() ran a reactive pipeline per notifier, and each branch both sent the notification and created an in-app Notification. With two notifiers, the user got two in-app messages for the same event.
The fix
.flatMap(descriptor -> prepareNotificationElement(subscriber, reason, descriptor))
.collectList()
.filter(elements -> !elements.isEmpty())
.flatMap(elements -> {
var dispatchMono = Flux.fromIterable(elements)
.flatMap(this::sendNotification)
.then();
if (subscriber.isAnonymous()) {
return dispatchMono;
}
// create notification for user
var innerNotificationMono = createNotification(elements.get(0));
return Mono.when(dispatchMono, innerNotificationMono);
})
The change also fixes a variable name typo (innerNofificationMono). A new test sets up two notifiers and verifies two sends and one in-app notification:
verify(spyNotificationCenter, times(2)).sendNotification(any());
verify(spyNotificationCenter, times(1)).createNotification(any());
By the numbers
- Repository: halo-dev/halo, 40,107 stars (Nov 3, 2026), Java, GPL-3.0
- Files changed: 2 (1 source file, 1 test file)
- Lines: +42 / -4
- Commits: 1
- Opened: Aug 21, 2026. Merged: Aug 25, 2026. Time to merge: 3 days, 20 hours
- Review: approved and merged by a maintainer; CLA signed; quality gate passed
How the review went
The PR included a release note: "Fix duplicate in-app notifications when multiple notifiers are enabled." Automated checks reported the quality gate passed and 87.5% patch coverage. A maintainer approved and merged it without requesting changes.
Preguntas frecuentes
Do external notifiers still each receive the message?
Yes. Every enabled notifier still gets a send. Only the in-app notification is deduplicated.
Where can I read more?
See the pull request and the original issue.
el objetivo
Reactive pipelines make it easy to do one thing per element when you meant to do it once. Collecting first, then splitting the side effects, states the intent in the code.