Problem
dbl cancel names every failed cancellation a rejection unless the server answered an HTTP 5xx. At 8255ba5 (#161) cancelFailureName in cmd/dbl/query.go (lines 145-151) is:
var httpErr *client.HTTPError
if errors.As(err, &httpErr) && httpErr.StatusCode >= http.StatusInternalServerError {
return "dbl cancel: cancellation not confirmed"
}
return "dbl cancel: cancellation rejected"
A transport failure is not an *HTTPError: when c.http.Do fails, pkg/client/transport.go do (lines 92-94) returns the unexported *transportError built by wrapTransport (lines 129-143). That includes a connection reset or a context deadline exceeded from the client's own per-request timeout after the DELETE /debuglet request has been sent. In that case the dispatcher may have received the request, aborted the run and recorded the result, yet the user reads
dbl cancel: cancellation rejected: client: DELETE /debuglet: context deadline exceeded
At 10f0f4f the wording is the same for every error, including the 5xx.
Expected behaviour
A cancellation whose outcome is unknown is reported as unconfirmed, with the advice to read the state and repeat the cancellation (the guidance docs/CLI.md gives for the 500). Only a refusal by the server (4xx, cancel_refused) and a local validation failure (invalid job ID, blank executor) are rejections. The exit code stays 1 in both cases.
Proposed change
Let pkg/client expose whether an error is a transport failure (an exported predicate or an exported error type; transportError already implements Unwrap), and let cancelFailureName name transport failures and 5xx answers "cancellation not confirmed". reportFailure in cmd/dbl/cli.go already distinguishes the command's own deadline and interruption; this change concerns the request-level failure it cannot see.
Acceptance
Problem
dbl cancelnames every failed cancellation a rejection unless the server answered an HTTP 5xx. At 8255ba5 (#161)cancelFailureNameincmd/dbl/query.go(lines 145-151) is:A transport failure is not an
*HTTPError: whenc.http.Dofails,pkg/client/transport.godo(lines 92-94) returns the unexported*transportErrorbuilt bywrapTransport(lines 129-143). That includes a connection reset or acontext deadline exceededfrom the client's own per-request timeout after theDELETE /debugletrequest has been sent. In that case the dispatcher may have received the request, aborted the run and recorded the result, yet the user readsAt 10f0f4f the wording is the same for every error, including the 5xx.
Expected behaviour
A cancellation whose outcome is unknown is reported as unconfirmed, with the advice to read the state and repeat the cancellation (the guidance
docs/CLI.mdgives for the 500). Only a refusal by the server (4xx,cancel_refused) and a local validation failure (invalid job ID, blank executor) are rejections. The exit code stays 1 in both cases.Proposed change
Let
pkg/clientexpose whether an error is a transport failure (an exported predicate or an exported error type;transportErroralready implementsUnwrap), and letcancelFailureNamename transport failures and 5xx answers "cancellation not confirmed".reportFailureincmd/dbl/cli.goalready distinguishes the command's own deadline and interruption; this change concerns the request-level failure it cannot see.Acceptance
cmd/dbl/receipts_test.go: aDELETE /debuglethandler that holds the request past the client's request timeout, and one that resets the connection, both makedbl cancelexit 1 with "cancellation not confirmed"; a 400cancel_refusedand an invalid ID still print "cancellation rejected".docs/CLI.mddescribes the three outcomes ofdbl cancel: acknowledged, rejected, not confirmed.