fix(login): retry transient poll errors instead of aborting the device flow
A proxy 502 during a backend restart killed attended logins mid-poll. NotFound/InvalidArgument still fail fast; everything else retries until the device-code deadline, with a one-time notice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
2b685348c9
commit
4e82b1ef41
@ -38,11 +38,19 @@ func newLoginCmd() *cobra.Command {
|
|||||||
fmt.Printf("Visit %s?user_code=%s to authorize.\n", start.Msg.VerificationUri, start.Msg.UserCode)
|
fmt.Printf("Visit %s?user_code=%s to authorize.\n", start.Msg.VerificationUri, start.Msg.UserCode)
|
||||||
interval := time.Duration(start.Msg.IntervalSeconds) * time.Second
|
interval := time.Duration(start.Msg.IntervalSeconds) * time.Second
|
||||||
deadline := time.Now().Add(time.Duration(start.Msg.ExpiresInSeconds) * time.Second)
|
deadline := time.Now().Add(time.Duration(start.Msg.ExpiresInSeconds) * time.Second)
|
||||||
|
warned := false
|
||||||
for time.Now().Before(deadline) {
|
for time.Now().Before(deadline) {
|
||||||
time.Sleep(interval)
|
time.Sleep(interval)
|
||||||
poll, err := cli.Auth.PollDevice(ctx, connect.NewRequest(&v1.PollDeviceRequest{DeviceCode: start.Msg.DeviceCode}))
|
poll, err := cli.Auth.PollDevice(ctx, connect.NewRequest(&v1.PollDeviceRequest{DeviceCode: start.Msg.DeviceCode}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
if !pollRetryable(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !warned {
|
||||||
|
fmt.Printf("Temporary error while waiting for approval (will keep trying): %v\n", err)
|
||||||
|
warned = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
switch poll.Msg.Status {
|
switch poll.Msg.Status {
|
||||||
case "pending":
|
case "pending":
|
||||||
@ -82,6 +90,18 @@ func newLoginCmd() *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pollRetryable reports whether a PollDevice error is worth retrying until
|
||||||
|
// the device-code deadline. Transient transport failures (a proxy 502 while
|
||||||
|
// the backend restarts, timeouts) must not abort an attended login; NotFound
|
||||||
|
// and InvalidArgument mean the server can never approve this code.
|
||||||
|
func pollRetryable(err error) bool {
|
||||||
|
switch connect.CodeOf(err) {
|
||||||
|
case connect.CodeNotFound, connect.CodeInvalidArgument:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func newWhoamiCmd() *cobra.Command {
|
func newWhoamiCmd() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "whoami",
|
Use: "whoami",
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"connectrpc.com/connect"
|
||||||
|
|
||||||
"git.dev.alexdunmow.com/block/cli/internal/creds"
|
"git.dev.alexdunmow.com/block/cli/internal/creds"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,3 +28,18 @@ func TestApplyPolledAccount_EmptyFallsThrough(t *testing.T) {
|
|||||||
t.Fatalf("hc = %+v, want untouched", hc)
|
t.Fatalf("hc = %+v, want untouched", hc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPollRetryable(t *testing.T) {
|
||||||
|
if pollRetryable(connect.NewError(connect.CodeNotFound, errors.New("unknown device code"))) {
|
||||||
|
t.Error("NotFound must not be retried — the server no longer knows the code")
|
||||||
|
}
|
||||||
|
if pollRetryable(connect.NewError(connect.CodeInvalidArgument, errors.New("device_code is required"))) {
|
||||||
|
t.Error("InvalidArgument must not be retried")
|
||||||
|
}
|
||||||
|
if !pollRetryable(connect.NewError(connect.CodeUnavailable, errors.New("unavailable: 502 Bad Gateway"))) {
|
||||||
|
t.Error("Unavailable (proxy 502 during backend restart) must be retried")
|
||||||
|
}
|
||||||
|
if !pollRetryable(errors.New("plain network error")) {
|
||||||
|
t.Error("non-connect errors must be retried")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user