Skip to content

Retry a failed run report without waiting for another file (watcher 1.2.2) - #325

Merged
wasimxyz merged 3 commits into
stagingfrom
watcher-run-report-retry
Oct 16, 2026
Merged

wasimxyz merged 3 commits into
stagingfrom
watcher-run-report-retry

Conversation

@wasimxyz

@wasimxyz wasimxyz commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Closes #245. Supersedes #246.

Problem

When the watcher's first report of a run to Data Hub fails because of a short connection problem, the run stays unreported until another file in that run finishes writing, or until the watcher restarts. A single-file run, or a run whose last file just finished, can wait for days. In automatic mode the file is not uploaded either.

What changed

The first commit is the fix from #246 by @RowletCC, with their authorship kept. It retries a failed report on the monitor's existing once-per-second loop, so no new file or restart is needed. The later commits tidy and extend it.

  • A failed report is retried after 5 seconds, then after waits that double up to 5 minutes. It keeps retrying every 5 minutes until the report goes through, so an outage of any length clears on its own.
  • Connection errors, 5xx responses, and any other error the client raises (for example a connection that drops mid-response, or a proxy's HTML page instead of JSON) are retried, on the first attempt as well as on retries. A 4xx needs a person to fix the cause and is never retried. An error after the server accepted the report, such as a local database write failing, is not a failed report and is handled as before.
  • run_report_failed is recorded once for a row of retried failures, even if more files in the run finish during the outage, so a long outage doesn't fill the 500-event queue. A 4xx is still recorded every time. The heartbeat's error count still counts every attempt.
  • A new file during an outage is still sent right away, and a failure there keeps the run's backoff instead of restarting it.
  • A failed update to an existing run is retried the same way. In automatic mode that update also decides whether the new file gets uploaded.
  • Removed the 429 and Retry-After handling from Retry transient watcher run reports without new file events #246. Data Hub never sends either to the watcher.
  • ApiError.is_transient holds the "no response or 5xx" rule, and the uploader now uses it too.
  • The retry delays are named in constants.py, the monitor hook is called on_tick, and the tests live in test_run_detector.py and test_monitor_events.py.

Replaying a report is safe: the server inserts a run only when its instrument and run ID are new, sends notifications only for new runs, and skips files it already has.

Release

  • Watcher 1.2.2, with uv.lock, the CLI catalog, and the docs bundle regenerated.
  • Added a changelog entry, a release table row, a troubleshooting section, and developer docs for the retry behavior.
  • The changelog file is dated today. Rename it if this merges on a later day.
  • Tagging watcher-v1.2.2 and setting Latest version in Settings → Watchers happen after this reaches production.

How I tested it

  • All 507 watcher unit tests pass, and make check passes, which includes docs-links.
  • I broke these behaviors on purpose and a test failed for each: reporting a 4xx during retries, catching only ApiError on the first attempt, and restarting the backoff when a new file arrives.
  • Before the last commit, I ran a watcher against the local dev server through a small proxy and a throwaway instrument. I stopped the proxy, dropped a one-file run into the watched folder, and watched the retries at 5 and 10 seconds. I restarted the proxy before the third retry, and the run appeared on its own with no restart and no second file. The server's event log held exactly one run_report_failed event. I deleted the throwaway rows afterward. The last commit doesn't change that path.

RowletCC and others added 2 commits October 16, 2026 13:57
Builds on the previous commit, which retries a run report that fails with a
connection error or a server error. This commit limits the retries and
tidies the code around them.

- Stop after 16 retries (about 55 minutes), then send one
  `run_report_retries_exhausted` event. A new file in the run starts a fresh
  window, and so does a restart.
- Send `run_report_failed` for the first failure of a window instead of every
  attempt. A 4xx is still sent every time, because it is not retried.
- Remove the 429 and `Retry-After` handling. Data Hub never sends either to
  the watcher.
- Count an unexpected error during a retry as a failed attempt. Before, it
  dropped the run from the retry list.
- Keep the due times in one dictionary on `RunDetector`, name the delays in
  `constants.py`, and rename the monitor hook to `on_tick`.
- Move the tests into `test_run_detector.py` and `test_monitor_events.py`.
- Bump the watcher to 1.2.2, regenerate the CLI catalog and docs bundle, and
  add developer docs, a release table row, a troubleshooting section, and a
  changelog entry.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
data-hub Ready Ready Preview Oct 16, 2026 9:24pm UTC
data-hub-docs Ready Ready Preview Oct 16, 2026 9:24pm UTC

Request Review

- Retry at the 5-minute cap until the report goes through, instead of
  stopping after 16 retries. Remove MAX_RUN_REPORT_RETRIES and the
  run_report_retries_exhausted event.
- Treat any error the client raises, not just ApiError, as a failed
  attempt on the first try as well as on retries. An error after the
  server accepted the report still propagates as before.
- Keep the backoff when a new file arrives during an outage, so a run
  that keeps producing files records one run_report_failed event.
- Clear the retry state after a 4xx.
- Add ApiError.is_transient and use it in the uploader too.
- Update docs, the changelog entry, and the MCP docs bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
@wasimxyz
wasimxyz merged commit be1c28e into staging Oct 16, 2026
8 checks passed
@wasimxyz
wasimxyz deleted the watcher-run-report-retry branch October 16, 2026 21:26

This branch was successfully deployed

2 active deployments
Preview – data-hub — 1ba463a8 Deployed Oct 16, 2026 by vercel[bot]
Preview – data-hub-docs — 1ba463a8 Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Watcher can strand a single-file run after transient report failure

2 participants