Skip to content

fix: reset push monitor retries when UP heartbeat is received#7081

Open
viceice wants to merge 1 commit intolouislam:masterfrom
viceice:fix/heartbeat-retry-reset
Open

fix: reset push monitor retries when UP heartbeat is received#7081
viceice wants to merge 1 commit intolouislam:masterfrom
viceice:fix/heartbeat-retry-reset

Conversation

@viceice
Copy link
Copy Markdown

@viceice viceice commented Mar 3, 2026

Summary

In this pull request, the following changes are made:

  • reset the retry counter when push monitor receives an UP ( or DOWN if upside down) and persists it.
  • i did not used any AI but copied code from previous PR.
  • Need help for how to best test this
Please follow this checklist to avoid unnecessary back and forth (click to expand)
  • ⚠️ If there are Breaking change (a fix or feature that alters existing functionality in a way that could cause issues) I have called them out
  • 🧠 I have disclosed any use of LLMs/AI in this contribution and reviewed all generated content.
    I understand that I am responsible for and able to explain every line of code I submit.
  • 🔍 Any UI changes adhere to visual style of this project.
  • 🛠️ I have self-reviewed and self-tested my code to ensure it works as expected.
  • 📝 I have commented my code, especially in hard-to-understand areas (e.g., using JSDoc for methods).
  • 🤖 I added or updated automated tests where appropriate.
  • 📄 Documentation updates are included (if applicable).
  • 🧰 Dependency updates are listed and explained.
  • ⚠️ CI passes and is green.

Screenshots for Visual Changes

not applicable

Copilot AI review requested due to automatic review settings March 3, 2026 07:43
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 3, 2026

Hello and thanks for lending a paw to Uptime Kuma! 🐻👋
As this is your first contribution, please be sure to check out our Pull Request guidelines.
In particular: - Mark your PR as Draft while you’re still making changes - Mark it as Ready for review once it’s fully ready
If you have any design or process questions, feel free to ask them right here in this pull request - unclear documentation is a bug too.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to ensure push monitors don’t keep accumulating retry counts after a successful heartbeat, by persisting a retry reset when a valid heartbeat is detected during the push monitor’s scheduled check loop.

Changes:

  • Persist retry reset for push monitors by writing retries = 0 back to the last successful heartbeat record when the heartbeat is within the allowed time window.

Comment on lines +755 to +758
// Update the previous heartbeat's retries to 0 to persist the reset
if (previousBeat.retries > 0) {
previousBeat.retries = 0;
await R.store(previousBeat);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reset persists by updating previousBeat, but in this code path previousBeat is selected via ORDER BY time DESC (see earlier in start()), while heartbeat.time is defined as a plain DATETIME in the schema (no millisecond precision). On MariaDB/MySQL this can result in multiple heartbeats sharing the same time value within the same second, making ORDER BY time DESC non-deterministic and potentially causing the wrong row to be updated (so the retry counter may still not reliably reset). Consider selecting/updating the latest heartbeat deterministically (e.g., ORDER BY time DESC, id DESC or using the same MAX(id) approach as Monitor.getPreviousHeartbeat()) before persisting the retries reset.

Suggested change
// Update the previous heartbeat's retries to 0 to persist the reset
if (previousBeat.retries > 0) {
previousBeat.retries = 0;
await R.store(previousBeat);
// Update the latest heartbeat's retries to 0 to persist the reset
if (previousBeat.retries > 0) {
const latestBeat = await R.findOne(
"heartbeat",
" monitor_id = ? ORDER BY time DESC, id DESC ",
[ this.id ]
);
if (latestBeat && latestBeat.retries > 0) {
latestBeat.retries = 0;
await R.store(latestBeat);
}

Copilot uses AI. Check for mistakes.
@CommanderStorm CommanderStorm added the pr:needs review this PR needs a review by maintainers or other community members label Mar 8, 2026
Copy link
Copy Markdown

@mahdirajaee mahdirajaee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addresses a real bug -- if a push monitor accumulates retries and then receives a healthy heartbeat, the retry counter should reset. Without this fix, the stale retry count persists in the database and can cause incorrect behavior on subsequent timeout evaluations.

The implementation looks correct. A couple of observations:

  1. The conditional if (previousBeat.retries > 0) is a good guard to avoid unnecessary writes to the database on every successful heartbeat. Only persisting when there is actually something to reset keeps the I/O minimal.

  2. One thing to verify: is there a potential race condition if two heartbeats arrive in rapid succession? The previousBeat reference is loaded earlier in the flow, so if a concurrent heartbeat modifies it between the read and this R.store(), you could get a stale write. In practice this is likely fine for push monitors since they are externally driven and unlikely to overlap, but worth thinking about.

  3. The in-memory retries = 0 reset was already present before this PR. The key addition here is persisting that reset to the database via previousBeat.retries = 0 + R.store(), which is the actual fix for the issue.

Solid fix. Would be good to have a test case that verifies the retry count resets in the database after a successful push heartbeat, as the author mentioned in the PR description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:needs review this PR needs a review by maintainers or other community members

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Push monitor retries not reset after a heartbeat is received

4 participants