Try a feed again in minutes when its host could not be looked up for the moment (#143)
205 of the Directory's 208 feeds without a category had never been read: on 2026-10-05 at 03:24 UTC every one failed with "dns error: ... Temporary failure in name resolution" within a minute, during an outage on Tower that also stopped iPX's log reaching Loki until Tower rebooted at 11:56. They are working podcasts, NPR's, Megaphone's, Acast's, which resolve now. A feed nobody subscribes to is read once a day and a failing one backs off up to a day (#99), so each sat failing, unread and so uncategorised (#117) until the next day, and explain_failure called every DNS error "This address no longer resolves; the site is gone.", on its page and since #142 on its Directory page. A forced check of the 208 read 205; each has its items, its description and its own category now. A temporary lookup failure, EAI_AGAIN, is not recorded on the feed at all: no last_error, no error_since to back off from or call it gone by. The daemon notes it in Ctx::retry and the feed is due again in ten minutes, which the scan's due check and the sleep until the next scan both honour; a restart forgets it, which only makes the retry sooner. A name that does not exist is still the feed's error, explained as "may be gone", and the Directory page, like the feed's own, names a cause only once a feed has been failing a day; before that its last check failed. The page also drops "Nobody here subscribes yet", which said nothing worth a line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
27
src/feed.rs
27
src/feed.rs
@@ -196,15 +196,25 @@ pub fn explain_failure(msg: &str) -> Option<Failure> {
|
||||
if low.contains("http 402") {
|
||||
return Some(Failure { reason: "The feed now needs a paid plan.", new_url: None });
|
||||
}
|
||||
if low.contains("dns error")
|
||||
|| low.contains("failed to lookup address")
|
||||
|| low.contains("no address associated")
|
||||
// Only a name that does not exist. A lookup that failed for the moment says nothing about the
|
||||
// site, and NPR's and Megaphone's feeds were labelled gone after a DNS outage (#143).
|
||||
if !is_temporary_lookup_failure(msg)
|
||||
&& (low.contains("dns error") || low.contains("failed to lookup address") || low.contains("no address associated"))
|
||||
{
|
||||
return Some(Failure { reason: "This address no longer resolves; the site is gone.", new_url: None });
|
||||
return Some(Failure { reason: "This address no longer resolves; the site may be gone.", new_url: None });
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// A host that could not be looked up for the moment -- the resolver's EAI_AGAIN, glibc's
|
||||
/// "Temporary failure in name resolution", musl's "Try again" -- as against a name that does
|
||||
/// not exist ("Name or service not known"). It says the network was not answering, not that the
|
||||
/// feed is gone (#143).
|
||||
pub fn is_temporary_lookup_failure(msg: &str) -> bool {
|
||||
let low = msg.to_ascii_lowercase();
|
||||
low.contains("dns error") && (low.contains("temporary failure in name resolution") || low.contains("try again"))
|
||||
}
|
||||
|
||||
/// True when a body is an OPML document rather than a feed.
|
||||
///
|
||||
/// The original matched on the URL ending in ".opml" (iPXClass.py:34), which misses an
|
||||
@@ -1317,8 +1327,13 @@ mod tests {
|
||||
explain_failure("the feed's address answered with nothing at all").unwrap().reason,
|
||||
"This address answers with nothing; the site may be gone."
|
||||
);
|
||||
let dns = explain_failure("connecting: dns error: failed to lookup address information").unwrap();
|
||||
assert_eq!(dns.reason, "This address no longer resolves; the site is gone.");
|
||||
let dns = explain_failure("connecting: dns error: failed to lookup address information: Name or service not known").unwrap();
|
||||
assert_eq!(dns.reason, "This address no longer resolves; the site may be gone.");
|
||||
// A lookup that failed for the moment is not a site gone (#143).
|
||||
let blip = "connecting: dns error: failed to lookup address information: Temporary failure in name resolution";
|
||||
assert!(is_temporary_lookup_failure(blip));
|
||||
assert!(explain_failure(blip).is_none());
|
||||
assert!(!is_temporary_lookup_failure("connecting: dns error: failed to lookup address information: Name or service not known"));
|
||||
let moved = explain_failure("got a web page, not a feed; it links https://x/feed as its feed").unwrap();
|
||||
assert_eq!(moved.new_url.as_deref(), Some("https://x/feed"));
|
||||
assert!(explain_failure("got a web page, not a feed").unwrap().new_url.is_none());
|
||||
|
||||
Reference in New Issue
Block a user