This is an automated email from the ASF dual-hosted git repository.
gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new a4d2630320 [fix] fix cyclic silence time matching and cross-midnight
handling (#4081)
a4d2630320 is described below
commit a4d2630320734e952e2abab0b5be16e4e4088230
Author: shown <[email protected]>
AuthorDate: Sun Mar 22 22:05:27 2026 +0800
[fix] fix cyclic silence time matching and cross-midnight handling (#4081)
Co-authored-by: yunfan24 <[email protected]>
Co-authored-by: Tomsun28 <[email protected]>
---
.../hertzbeat/alert/reduce/AlarmSilenceReduce.java | 34 +++++++--
.../alert/reduce/AlarmSilenceReduceTest.java | 82 ++++++++++++++++++++++
2 files changed, 112 insertions(+), 4 deletions(-)
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduce.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduce.java
index 4fdf27746b..7dfad6360d 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduce.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduce.java
@@ -18,6 +18,7 @@
package org.apache.hertzbeat.alert.reduce;
import java.time.LocalDateTime;
+import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -95,10 +96,35 @@ public class AlarmSilenceReduce {
* @return true if alert should not be silenced, false if alert should be
silenced
*/
private boolean checkAndSave(LocalDateTime now, AlertSilence alertSilence)
{
- boolean startMatch = alertSilence.getPeriodStart() == null
- ||
now.isAfter(alertSilence.getPeriodStart().toLocalDateTime());
- boolean endMatch = alertSilence.getPeriodEnd() == null
- || now.isBefore(alertSilence.getPeriodEnd().toLocalDateTime());
+ boolean startMatch;
+ boolean endMatch;
+ if (alertSilence.getType() == 1) {
+ LocalTime nowTime = now.toLocalTime();
+ LocalTime startTime = alertSilence.getPeriodStart() == null ? null
: alertSilence.getPeriodStart().toLocalTime();
+ LocalTime endTime = alertSilence.getPeriodEnd() == null ? null :
alertSilence.getPeriodEnd().toLocalTime();
+ if (startTime == null && endTime == null) {
+ startMatch = true;
+ endMatch = true;
+ } else if (startTime == null) {
+ startMatch = true;
+ endMatch = !nowTime.isAfter(endTime);
+ } else if (endTime == null) {
+ startMatch = !nowTime.isBefore(startTime);
+ endMatch = true;
+ } else if (!startTime.isAfter(endTime)) {
+ startMatch = !nowTime.isBefore(startTime);
+ endMatch = !nowTime.isAfter(endTime);
+ } else {
+ // Cross-midnight window, e.g. 23:00-02:00.
+ startMatch = !nowTime.isBefore(startTime) ||
!nowTime.isAfter(endTime);
+ endMatch = true;
+ }
+ } else {
+ startMatch = alertSilence.getPeriodStart() == null
+ ||
now.isAfter(alertSilence.getPeriodStart().toLocalDateTime());
+ endMatch = alertSilence.getPeriodEnd() == null
+ ||
now.isBefore(alertSilence.getPeriodEnd().toLocalDateTime());
+ }
if (startMatch && endMatch) {
int time = Optional.ofNullable(alertSilence.getTimes()).orElse(0);
diff --git
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduceTest.java
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduceTest.java
index b9bc9ea9df..2c9d7d0e42 100644
---
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduceTest.java
+++
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/reduce/AlarmSilenceReduceTest.java
@@ -119,6 +119,88 @@ class AlarmSilenceReduceTest {
verify(alertSilenceDao).save(silenceRule);
}
+ @Test
+ void
whenCyclicSilenceRuleTimeMatchesButDateDifferent_shouldNotForwardAlert() {
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime yesterday = now.minusDays(1);
+ LocalDateTime start = yesterday.withHour(now.getHour())
+ .withMinute(Math.max(0, now.getMinute() - 10))
+ .withSecond(0)
+ .withNano(0);
+ LocalDateTime end = yesterday.withHour(now.getHour())
+ .withMinute(Math.min(59, now.getMinute() + 10))
+ .withSecond(59)
+ .withNano(0);
+
+ AlertSilence silenceRule = AlertSilence.builder()
+ .enable(true)
+ .matchAll(false)
+ .type((byte) 1)
+ .labels(createLabels("service", "web"))
+ .periodStart(start.atZone(ZoneId.systemDefault()))
+ .periodEnd(end.atZone(ZoneId.systemDefault()))
+ .days(Collections.singletonList((byte)
now.getDayOfWeek().getValue()))
+ .times(0)
+ .build();
+
+
when(alertSilenceDao.findAlertSilencesByEnableTrue()).thenReturn(Collections.singletonList(silenceRule));
+
when(alertSilenceDao.save(any(AlertSilence.class))).thenReturn(silenceRule);
+
+ GroupAlert alert = createGroupAlert("firing", createLabels("service",
"web"));
+ alarmSilenceReduce.silenceAlarm(alert);
+
+ verify(alertNoticeDispatch, never()).dispatchAlarm(alert);
+ verify(alertSilenceDao).save(silenceRule);
+ }
+
+ @Test
+ void whenMatchingCrossMidnightCyclicSilenceRule_shouldNotForwardAlert() {
+ LocalDateTime now = LocalDateTime.now();
+ AlertSilence silenceRule = AlertSilence.builder()
+ .enable(true)
+ .matchAll(false)
+ .type((byte) 1)
+ .labels(createLabels("service", "web"))
+ .periodStart(now.minusHours(1).atZone(ZoneId.systemDefault()))
+ .periodEnd(now.minusHours(2).atZone(ZoneId.systemDefault()))
+ .days(Collections.singletonList((byte)
now.getDayOfWeek().getValue()))
+ .times(0)
+ .build();
+
+
when(alertSilenceDao.findAlertSilencesByEnableTrue()).thenReturn(Collections.singletonList(silenceRule));
+
when(alertSilenceDao.save(any(AlertSilence.class))).thenReturn(silenceRule);
+
+ GroupAlert alert = createGroupAlert("firing", createLabels("service",
"web"));
+ alarmSilenceReduce.silenceAlarm(alert);
+
+ verify(alertNoticeDispatch, never()).dispatchAlarm(alert);
+ verify(alertSilenceDao).save(silenceRule);
+ }
+
+ @Test
+ void
whenCrossMidnightCyclicSilenceRuleDoesNotIncludeCurrentDay_shouldForwardAlert()
{
+ LocalDateTime now = LocalDateTime.now();
+ byte previousDay = (byte) now.minusDays(1).getDayOfWeek().getValue();
+ AlertSilence silenceRule = AlertSilence.builder()
+ .enable(true)
+ .matchAll(false)
+ .type((byte) 1)
+ .labels(createLabels("service", "web"))
+ .periodStart(now.minusHours(1).atZone(ZoneId.systemDefault()))
+ .periodEnd(now.minusHours(2).atZone(ZoneId.systemDefault()))
+ .days(Collections.singletonList(previousDay))
+ .times(0)
+ .build();
+
+
when(alertSilenceDao.findAlertSilencesByEnableTrue()).thenReturn(Collections.singletonList(silenceRule));
+
+ GroupAlert alert = createGroupAlert("firing", createLabels("service",
"web"));
+ alarmSilenceReduce.silenceAlarm(alert);
+
+ verify(alertNoticeDispatch).dispatchAlarm(alert);
+ verify(alertSilenceDao, never()).save(any());
+ }
+
@Test
void whenSilenceRuleExpired_shouldForwardAlert() {
AlertSilence silenceRule = AlertSilence.builder()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]