The binary make install builds retries a refused or unresolvable connection (closes #206)
check / check (push) Waiting to run
check / check (push) Waiting to run
Bun's `fetch`, which `~/bin/quak` runs under, rejects with a plain `Error` that has no `cause` and a code of bun's own. Running the built binary against local listeners gave `ConnectionRefused` for a refused connection and a failed TLS handshake, and `ConnectionRefused` or `FailedToOpenSocket` for a name that does not resolve. Both join `TRANSPORT_CODES` in `src/retry.ts`, so they are retried and called transient. They stay out of `CONNECT_CODES`, so a `POST` or `PUT` is not replayed on them, because bun also gives them when it resends a request on a new connection. `classify` in `src/backup.ts` records a `TimeoutError` as transient, so a stalled download is no longer `unknown`. Not changed: a certificate bun rejects is not retried. Model: opus-5-5
This commit is contained in:
@@ -151,7 +151,9 @@ for each, separated by `, `. A file whose download failed that way is in
|
||||
`failures.json` with that error, as a transient failure. So is each file with no
|
||||
ML data cached when the ML data fetch failed that way, its error starting
|
||||
`ML data: `. The `~/bin/quak` that `make install` builds runs under bun, and
|
||||
prints bun's own wording for such a failure.
|
||||
prints bun's own wording for such a failure, with no reason after it, such as
|
||||
`quak: Unable to connect. Is the computer able to access the url?` for a refused
|
||||
connection. It records such a failure in `failures.json` as transient too.
|
||||
|
||||
After a `1`, the next run fetches each missing original again, fetches the ML
|
||||
data that is not cached, and rebuilds the album links. An album quak could not
|
||||
@@ -494,6 +496,17 @@ request is repeated only when repeating it could produce a different answer:
|
||||
declining to retry a transient one costs a single file that the next run picks
|
||||
up.
|
||||
|
||||
The `~/bin/quak` that `make install` builds runs under bun, whose `fetch`
|
||||
rejects with a plain `Error` that has no `cause` and carries a code of bun's
|
||||
own. quak retries a refused connection, a name that does not resolve, a reset
|
||||
connection and a deadline under bun as it does under Node. Bun reports a refused
|
||||
connection, and a TLS handshake that failed, as `ConnectionRefused`. For a name
|
||||
that does not resolve it gives `ConnectionRefused` on some requests and
|
||||
`FailedToOpenSocket` on others. A connection reset or closed before the response
|
||||
ended is `ECONNRESET`, as under Node, and a deadline is the same `TimeoutError`.
|
||||
A certificate bun rejects, reported with a code such as
|
||||
`DEPTH_ZERO_SELF_SIGNED_CERT`, is not retried.
|
||||
|
||||
Backoff is exponential with full jitter: the delay before retry _n_ is
|
||||
`random() * min(maxDelayMs, baseDelayMs * 2 ** (n - 1))`. The exponential term
|
||||
is the ceiling and the wait is drawn below it, so a client that lost many
|
||||
@@ -549,9 +562,13 @@ routing errnos `EHOSTUNREACH`, `ENETUNREACH` and `ENETDOWN` are excluded for the
|
||||
same reason, despite looking like connect-time failures: on Linux an ICMP
|
||||
unreachable arriving mid-flight, or a local interface going down after the
|
||||
request was written, delivers them on an already-established socket. They stay
|
||||
retryable for the idempotent calls. `putFile` is exempt: a presigned PUT stores
|
||||
one whole object at one key in one request, so replaying it has no partial state
|
||||
to damage.
|
||||
retryable for the idempotent calls. So do bun's `ConnectionRefused` and
|
||||
`FailedToOpenSocket`, on which a `POST` or `PUT` is not replayed either. When a
|
||||
connection bun kept open from an earlier request closes before any answer, bun
|
||||
sends the request again on a new connection, and if that one fails it gives one
|
||||
of these codes although the server may already have the request. `putFile` is
|
||||
exempt: a presigned PUT stores one whole object at one key in one request, so
|
||||
replaying it has no partial state to damage.
|
||||
|
||||
A download is retried as a whole — request, stream consumption, and decryption —
|
||||
because a socket reset after the response headers have arrived surfaces in the
|
||||
|
||||
Reference in New Issue
Block a user