unbridled-41 opened a new issue, #4783:
URL: https://github.com/apache/rocketmq-dashboard/issues/4783

   ### Studio Version
   
   Trunk `rocketmq-studio` @ `4c697f07` (line references are as of that commit).
   
   ### Problem
   
   `POST /api/alert-rules/update` and `POST /api/cluster-alert-rules/update` 
replace every editable field of a rule, but an update body that simply omits an 
optional field does not clear it. `MybatisPlusAlertRepository.replaceRule` 
(`server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java:141-146`)
 builds the entity with `toRuleEntity` and calls 
`ruleMapper.updateById(entity)`. MyBatis-Plus's default NOT_NULL update 
strategy omits null entity fields from the UPDATE's SET clause, so the previous 
value silently survives.
   
   The service path makes the mismatch worse: `AlertService.updateRule` 
(`AlertService.java:190-223`) validates the submitted VO, replaces the stored 
rule, and returns the **submitted** VO. So the API responds with the field 
cleared (`consumerGroup`: null, `severity`: null, ...), the UI renders the 
cleared value, and the next `GET` shows the old value back.
   
   Fields affected (all nullable in `rmq_alert_rule`, all accepted-as-null by 
`NativeAlertRulePolicy.validate` and `AlertRuleRequestDTO`): `thresholdUnit`, 
`duration`, `channels`, `description`, `brokerName`, `clusterName`, `severity`, 
`instanceId` (for Prometheus-rule metrics only — native metrics require it), 
`consumerGroup`, `topic`, `notificationTemplate`.
   
   A concrete failure: a business `consumer.lag.total` rule scoped to 
`consumerGroup="G1"` cannot be re-scoped to all groups through the update API. 
The stale filter keeps narrowing alert evaluation while the operator believes 
it was removed.
   
   ### Evidence
   
   1. `NativeAlertRulePolicy.validate` only rejects a missing `instanceId` for 
native metrics (`NativeAlertRulePolicy.java:66-71`); a null 
`consumerGroup`/`topic`/`severity`/`duration` passes 
(`AlertRuleDuration.parse(null)` returns ZERO).
   2. `replaceRule` → `ruleMapper.updateById(toRuleEntity(rule))` with the 
entity's optional fields null — MyBatis-Plus skips them in the SET clause (no 
global `update-strategy` override in `application.yml`, no 
`@TableField(updateStrategy=...)` on `RmqAlertRule`).
   3. The codebase already documents this exact behaviour for the sibling path 
and works around it: `NameserverRegistryService.clearOmittedOptionalColumns` 
(`cluster/nameserver/NameserverRegistryService.java:147-172`, merged PR #4466, 
"MyBatis-Plus updateById omits null entity fields... assign those columns 
explicitly"), and `MybatisPlusInstanceRepository.java:128-131` does the same 
for a cleared credential reference. The alert-rule path is the one missing it.
   
   ### Impact
   
   - Scope filters 
(`instanceId`/`consumerGroup`/`topic`/`brokerName`/`clusterName`) cannot be 
cleared, so alerts keep evaluating against a stale narrower scope than the UI 
shows.
   - `severity`/`duration`/`channels`/`notificationTemplate`/`description` 
silently revert to their previous values after an update that omitted them, 
contradicting the 200 response.
   - The silent divergence between the response and the stored row is 
undetectable from the client.
   
   ### Expected behavior
   
   An update that omits an optional field clears it, and the stored rule 
matches the response — the same contract the registry and instance paths 
already implement.
   
   ### Related work
   
   - #4466 (merged 2026-09-21): the same defect class fixed for instance and 
nameserver-registry optional columns; did not touch alert rules.
   - #4277/#4276/#4275 (closed/unmerged attempts in the same family) confirm 
the pattern is recognised by the project.
   - #4326 (open): toggling wipes FIRING/ACK state — a different 
field-lifecycle defect on the same table.
   - #4748 (open, mine): reconcile abort for rules without a metric — unrelated.
   
   ## PR
   
   Fix: #… (opened together with this issue).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to