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:
25
src/web.rs
25
src/web.rs
@@ -1029,10 +1029,15 @@ struct Listed {
|
||||
items: Vec<ListedItem>,
|
||||
}
|
||||
|
||||
/// A feed's last error as its Directory page says it: explained, or that the check failed, never
|
||||
/// the error as it stands, which can name the feed's address, and the Directory names none.
|
||||
fn failure_words(err: &str) -> String {
|
||||
crate::feed::explain_failure(err).map_or_else(|| "Its last check failed.".to_owned(), |f| f.reason.to_owned())
|
||||
/// A feed's last error as its Directory page says it: explained once it has been failing a day, as
|
||||
/// the feed's own page does, or else that the check failed; never the error as it stands, which can
|
||||
/// name the feed's address, and the Directory names none. A day, so that a site down for an hour,
|
||||
/// or a resolver for a minute, is not called gone (#143).
|
||||
fn failure_words(err: &str, failing_for: i64) -> String {
|
||||
Some(err)
|
||||
.filter(|_| failing_for >= FLAG_AFTER_SECS)
|
||||
.and_then(crate::feed::explain_failure)
|
||||
.map_or_else(|| "Its last check failed.".to_owned(), |f| f.reason.to_owned())
|
||||
}
|
||||
|
||||
/// A listed feed's description and latest twenty items. Only a feed the Directory lists, so a
|
||||
@@ -1049,7 +1054,9 @@ async fn get_listed(
|
||||
let rows = state.ctx.db.entries_in(user.id, Some(&id), crate::db::Filter::parse("all"), None, 0, 20, &order).await?;
|
||||
let mut sanitizer = feed_sanitizer();
|
||||
let description = state.ctx.db.feed_description(&id).await?.map(|d| clean_description(&mut sanitizer, &d, None));
|
||||
let failing = state.ctx.db.feed_summary(&id).await?.last_error.as_deref().map(failure_words);
|
||||
let summary = state.ctx.db.feed_summary(&id).await?;
|
||||
let failing_for = summary.error_since.map_or(0, |since| crate::db::now() - since);
|
||||
let failing = summary.last_error.as_deref().map(|e| failure_words(e, failing_for));
|
||||
let items = rows
|
||||
.into_iter()
|
||||
.map(|e| ListedItem {
|
||||
@@ -1157,10 +1164,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_failing_feed_says_why_in_the_directory_without_its_address() {
|
||||
assert_eq!(failure_words("the feed's address answered with nothing at all"), "This address answers with nothing; the site may be gone.");
|
||||
let day = FLAG_AFTER_SECS;
|
||||
let nothing = "the feed's address answered with nothing at all";
|
||||
assert_eq!(failure_words(nothing, day), "This address answers with nothing; the site may be gone.");
|
||||
// Not before it has been failing a day, as on the feed's own page (#143).
|
||||
assert_eq!(failure_words(nothing, 3600), "Its last check failed.");
|
||||
// reqwest names the URL; the Directory names none.
|
||||
let raw = "error sending request for url (http://daily-quests.com/comic/?feed=atom): connection closed";
|
||||
assert_eq!(failure_words(raw), "Its last check failed.");
|
||||
assert_eq!(failure_words(raw, day), "Its last check failed.");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user