Skip to content

fix: improve retries and timeout handling - #179

Merged
bwplotka merged 1 commit into
bwplotka:mainfrom
vprashar2929:fix-ci
Oct 15, 2026
Merged

bwplotka merged 1 commit into
bwplotka:mainfrom
vprashar2929:fix-ci

Conversation

@vprashar2929

@vprashar2929 vprashar2929 commented Mar 4, 2026 •

Copy link
Copy Markdown
Contributor

Link checks can fail when a site drops a connection or returns a
temporary error. Retry these requests up to three times with backoff,
respect Retry-After, and stop retries when the context is canceled.

@vprashar2929
vprashar2929 force-pushed the fix-ci branch 3 times, most recently from cf7336f to f1f76e4 Compare March 5, 2026 08:22
@vprashar2929
vprashar2929 marked this pull request as draft March 5, 2026 08:22
@vprashar2929
vprashar2929 force-pushed the fix-ci branch 4 times, most recently from 719c0a4 to c93dfe9 Compare March 12, 2026 05:43
@vprashar2929 vprashar2929 changed the title fix: set proper User-Agent and add retry delay fix: improve retries and timeout handling Oct 7, 2026
@vprashar2929
vprashar2929 marked this pull request as ready for review October 7, 2026 18:48

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks!

Some suggestions, but overall nice!

Comment thread pkg/mdformatter/linktransformer/link.go
Comment thread pkg/mdformatter/linktransformer/link.go Outdated
http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
if retries < maxRetries {
response.Ctx.Put(numberOfRetriesKey, strconv.Itoa(retries+1))
v.remoteLinks[originalURL] = fmt.Errorf("%q not accessible, status code %v, retrying: %w", response.Request.URL.String(), response.StatusCode, err)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Why we set it if it will be overridden later?

Comment thread pkg/mdformatter/linktransformer/link.go Outdated
// Install the transport once to avoid races between async requests.
v.c.WithTransport(promhttp.RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
return promhttp.InstrumentRoundTripperCounter(
linktransformerMetrics.collyRequests,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Calling promhttp.InstrumentRoundTripperCounter and promhttp.InstrumentRoundTripperDuration inside RoundTripperFunc runs promhttp label validation and allocates a temporary prometheus.Registry on every request, redirect, and retry. Maybe wrap InstrumentRoundTripperCounter once outside RoundTripperFunc and observe collyPerDomainLatency directly?

Comment thread pkg/mdformatter/linktransformer/link.go
Comment thread pkg/mdformatter/linktransformer/link.go Outdated
}
retryAfter := response.Headers.Get("Retry-After")
// Limit the parsed integer to avoid overflowing time.Duration when converting seconds.
if seconds, err := strconv.ParseUint(retryAfter, 10, 32); err == nil {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

ParseUint(..., 10, 32) and http.ParseTime allow Retry-After values of hours or days, such as Retry-After: 3600, which will block mdox in OnError since v.c.Context has no deadline by default. Should we cap the maximum Retry-After delay or fail fast when a server asks to wait too long?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed

var requests int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
atomic.AddInt32(&requests, 1)
timer := time.NewTimer(31 * time.Second)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Since make test does not pass -short, this 31s sleep adds 31s to every test run. Could we test a short configured timeout like 100ms or check the configured transport field directly so unit tests stay fast?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

or use synctest

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

or use synctest

Not sure if synctest is available in the go version that we are using. But will take a look at it

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks!

Comment thread pkg/mdformatter/linktransformer/link.go
@vprashar2929

Copy link
Copy Markdown
Contributor Author

@bwplotka About the Slack link CI failure since Slack returns an unsupported browser message with Colly’s default User-Agent, but the same request with a browser User-Agent returns 200 locally. Would you prefer adding an ignore rule for this specific URL, or changing the User-Agent that mdox sends? WDYT?

@bwplotka

Copy link
Copy Markdown
Owner

I would ask if it makes to query slack urls on CI. On most or all cases you need to be authenticated. I would ensure users can put slack on some ignore list of known urls. I would reduce unnecessary network to endpoint to be a good citizen.

Link checks can fail when a site drops a connection or returns a
temporary error. Retry these requests up to three times with backoff,
respect Retry-After, and stop retries when the context is canceled.

Signed-off-by: vprashar2929 <vibhu.sharma2929@gmail.com>

@bwplotka bwplotka left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks!

@bwplotka
bwplotka merged commit 2a42135 into bwplotka:main Oct 15, 2026
4 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