feature/relayserver,net/udprelay,wgengine/magicsock: implement retry (#16347)

udprelay.Server is lazily initialized when the first request is received
over peerAPI. These early requests have a high chance of failure until
the first address discovery cycle has completed.

Return an ErrServerNotReady error until the first address discovery
cycle has completed, and plumb retry handling for this error all the
way back to the client in relayManager.

relayManager can now retry after a few seconds instead of waiting for
the next path discovery cycle, which could take another minute or
longer.

Updates tailscale/corp#27502

Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
Jordan Whited
2025-06-23 15:50:43 -07:00
committed by GitHub
parent 9288efe592
commit a589863d61
3 changed files with 99 additions and 37 deletions

View File

@@ -8,9 +8,11 @@ package relayserver
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"sync"
"time"
"tailscale.com/envknob"
"tailscale.com/feature"
@@ -184,6 +186,12 @@ func handlePeerAPIRelayAllocateEndpoint(h ipnlocal.PeerAPIHandler, w http.Respon
}
ep, err := rs.AllocateEndpoint(allocateEndpointReq.DiscoKeys[0], allocateEndpointReq.DiscoKeys[1])
if err != nil {
var notReady udprelay.ErrServerNotReady
if errors.As(err, &notReady) {
w.Header().Set("Retry-After", fmt.Sprintf("%d", notReady.RetryAfter.Round(time.Second)/time.Second))
httpErrAndLog(err.Error(), http.StatusServiceUnavailable)
return
}
httpErrAndLog(err.Error(), http.StatusInternalServerError)
return
}