The five channels that were still dropping a message the network ate, and an alert that would not stop repeating itself.
Added
-
ntfy, Gotify, Apprise and Matrix hold a failed notification and send it again when the connection comes back. They were the ones left out when the retry queue was built; each already had to be taught the difference between the network failing and the server saying no, because a rejected message retried every flush is a loop against something that will keep refusing it.
urllib.error.HTTPErroris a subclass ofURLError, so every one of the four had to be checked for the order of its handlers — a rejection caught by the network branch would be retried for fifteen minutes. -
SMTP holds one too, but only where that is safe. A failure while connecting, negotiating TLS or logging in means nothing reached the server, and those are retried. From the moment the message is handed over it is not: if the connection dies after
DATAthe server may well have accepted it, and e-mail has no transaction id to dedupe a second copy with. So a mail lost at that exact point stays lost — the lesser of the two. This does not fully close the gap (#66, @NotRetarded, who watches for outages through SMTP): an outage in the middle of a send still loses the alert.Classifying it is the whole job, and it is a trap:
smtplib.SMTPExceptionis a subclass ofOSError— measured — so the obviousexcept OSErrorwould file a wrong password and a refused recipient under "network trouble". The SMTP classes are asked first, and only what is left falls through to the socket errors. -
A container that keeps failing is reported less and less often. Thirty minutes between repeats is right for the first few; it is wrong for a crash loop nobody is going to fix tonight. @famewolf's
firefox-syncserverreached restart #190 and earned a message every half hour until he gave up and stopped the container — the alert was correct every single time, and the fortieth copy carried nothing the first did not. The wait now doubles per repeat up to six hours, so one broken container costs a handful of messages a day instead of forty-eight. It never goes silent: a channel that stops mentioning a broken container is how it gets forgotten, and a gap longer than the cap starts the count over, because that is a new incident rather than the old one continuing.
Fixed
- Matrix posted a duplicate when a send timed out after the homeserver had accepted it. The transaction id — the thing that makes a repeat harmless — was generated per attempt, while the comment beside it promised the opposite. It belongs to the message now, so a retry goes out under the id the homeserver already knows. This was wrong before the retry queue existed; the queue would have made it routine.
quit()could replace the error that caused the failure. It runs in afinallyand talks to the server, so on a broken connection it raises too — and an exception from afinallyreplaces the original. The classification then judged the wrong failure.