unbridled-41 opened a new pull request, #4826:
URL: https://github.com/apache/rocketmq-dashboard/pull/4826
## Problem / Evidence
The header stat "Triggered in 24h on page" (本页 24h 触发) on the alerts page
compares `new Date(r.lastTriggered).getTime()` against the wall clock
(`web/src/pages/ops/alerts.tsx`):
```ts
const triggered24h = rules.filter(
(r) => r.lastTriggered && new Date(r.lastTriggered).getTime() > dayAgo,
).length;
```
`lastTriggered` is a UTC `LocalDateTime` serialized **without an offset
suffix** (server: `NativeAlertProcessor` stamps
`LocalDateTime.ofInstant(collectedAt, ZoneOffset.UTC)` and persists it into
`last_triggered VARCHAR(64)`). The Last-Triggered column on the very same page
deliberately parses this value as UTC via `formatUtcDateTime` — with a comment
stating the convention — so the two displays of the same field disagree:
- Browser in UTC+8 (e.g. Asia/Shanghai, the dashboard's primary audience): a
rule that fired 23h ago UTC parses as 31h ago → **the stat undercounts**. The
column shows "fired 23h ago" while the stat excludes the rule.
- Browser in UTC−8: the same firing reads as 15h ago → the stat
**overcounts** (a firing 31h ago UTC is counted).
- Only a browser set to exactly UTC shows the right count.
The same fixture renders both wrong and right numbers on screen
simultaneously, so the defect is directly observable without any tooling.
## Root cause / Fix
The stat predates the UTC-parsing convention introduced for the column and
never adopted it.
Minimal fix:
- `web/src/utils/format.ts`: extract the parse rule into a new exported
`parseAlertTimestamp()` — an offset-less string is UTC (append `Z`), an
explicit offset is honored, unparseable values return `NaN`;
`formatUtcDateTime` now routes through it so the two call sites cannot drift
again.
- `web/src/pages/ops/alerts.tsx`: the stat filters on
`parseAlertTimestamp(r.lastTriggered) > dayAgo`.
## Priority / scoring
- Impact 24/40: a headline ops statistic silently miscounts by the viewer's
UTC offset, contradicting the adjacent column for the same data — misleads
on-call triage.
- Reach 14/20: the alerts page is the primary ops workflow; every visitor
outside UTC is affected.
- Reproducibility 18/20: fully deterministic under a fixed clock and TZ;
verified that the old code renders `0` and the fixed code `1` for the fixture
below under TZ=Asia/Shanghai.
- Maintenance value 8/20: collapses the parse convention into one helper,
preventing future drift.
- **PRIORITY 64/100**, **FIX_CONFIDENCE 95/100**.
## Tests
- `web/src/utils/format.test.ts`: four unit tests for `parseAlertTimestamp`
(offset-less ⇒ UTC, explicit `Z`/±hh:mm honored, blank/invalid ⇒ NaN, `Date`
passthrough).
- `web/src/pages/ops/__tests__/AlertsPage.test.tsx`: page-level regression
"counts the 24h-triggered stat against the UTC timestamp, not the browser zone"
— pins `Date.now` at 2026-08-24T12:00:00Z and `TZ=Asia/Shanghai`, feeds a rule
with `lastTriggered = '2026-08-23T13:00:00'` (23h old in UTC), asserts the stat
renders **1**. Verified against the pre-fix code: it rendered **0** under the
same conditions, so the test fails without the fix.
- `npx vitest run src/pages/ops/__tests__/AlertsPage.test.tsx
src/utils/format.test.ts` → 42 passed (42).
- `npx tsc --noEmit -p tsconfig.app.json` → clean; `npx eslint` on touched
files → no new findings (5 pre-existing warnings in alerts.tsx, present on the
clean tree).
## Risk
Low. `formatUtcDateTime` behavior is unchanged (its existing tests,
including explicit-offset and invalid-input cases, pass); the only behavior
change is the stat's parse convention, which now matches the column and the
system-alerts page.
--
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]