Skip to content

Retry transient download failures in the validator - #1145

Merged
chcg merged 1 commit into
notepad-plus-plus:masterfrom
krotname:validator-retry-transient-downloads
Jul 29, 2026
Merged

Retry transient download failures in the validator#1145
chcg merged 1 commit into
notepad-plus-plus:masterfrom
krotname:validator-retry-transient-downloads

Conversation

@krotname

Copy link
Copy Markdown
Contributor

validator.py downloads the archive of every plugin in the list on every run, with a single
requests.get that has no retries and no timeout. One dropped connection on any single entry —
including entries the pull request never touched — fails the whole job and hides the real result.

This is not hypothetical: in run 30290736279
the build (Release, x64) job lost four unrelated plugins at once:

CS-Script - C# Intellisense: ('Connection aborted.', ConnectionResetError(10054, ...))
Markdown Table Editor:       ('Connection aborted.', ConnectionResetError(10054, ...))
NppEventExec:                ('Connection aborted.', ConnectionResetError(10054, ...))
pycalc:                      ('Connection aborted.', ConnectionResetError(10054, ...))

All four are hosted on the GitHub release CDN, the job died in Validate json before MSBuild ever
ran, and build (Release, Win32) and build (Release, arm64) validated the very same JSON files
successfully in the same run. Only a maintainer can re-run the job, so a contributor is stuck
looking at a red check they cannot clear or explain.

Change

Downloads go through a requests.Session whose adapter retries connection errors and the usual
transient status codes (408, 425, 429, 500, 502, 503, 504) three times with exponential backoff,
plus a 60 second timeout so a hung host cannot stall the job indefinitely.

Error reporting is deliberately unchanged for real failures. raise_on_status=False keeps a
persistently non-200 response flowing into the existing status check with its original message, and
a host that stays unreachable still raises RequestException into the existing handler.

Worst case cost is bounded: a genuinely dead URL now takes about 12 extra seconds before it is
reported, and a healthy list costs nothing.

Verification

Against a local server that injects faults, using the session built by this change:

Scenario Attempts Outcome
clean download 1 200
2 connection resets, then 200 3 200
2 gateway timeouts, then 200 3 200
reset + 504, then 200 3 200
resets past the budget 4 ConnectionError raised, reported as before
504 past the budget 4 504 preserved, reported as before

The connection resets are real RSTs (SO_LINGER with a zero timeout), matching the WinError 10054
the runner saw.

python validator.py x86, x64 and arm64 all exit 0 against current master with this change,
with zero errors reported.

No new dependencies: requests.adapters.HTTPAdapter ships with requests, and urllib3 is already
pinned in requirements.txt.

Every run downloads the archive of every plugin in the list, so one dropped
connection or gateway timeout on any single entry fails the whole validation and
hides the real result. A recent run lost four unrelated plugins at once to
ConnectionResetError(10054) from the release CDN, while the same JSON validated
fine on the other two platforms.

Downloads now go through a session that retries connection errors and the usual
transient status codes three times with exponential backoff, and carries a
60 second timeout so a hung host cannot stall the job indefinitely. Permanent
failures are unchanged: a host that stays unreachable still raises and a status
that stays non-200 is still reported with the existing message, because the
retry policy does not raise on status.
@chcg chcg added this to the 1.9.8 milestone Jul 29, 2026
@chcg

chcg commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@krotname Thanks for the contribution to stabilise the download checks. Already had this on my list but didn't find the time for it.

@chcg
chcg merged commit 9afadc3 into notepad-plus-plus:master Jul 29, 2026
3 checks passed
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.

2 participants