mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-16 10:28:49 -07:00
Accept Retry-After header on discovery lookup failures
This commit is contained in:
parent
3008dc76d3
commit
9f2dc4554d
@ -44,6 +44,13 @@ type prioritizedAddress struct {
|
|||||||
addr string
|
addr string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An error may implement cachedError, in which case it will be interrogated
|
||||||
|
// to see how long we should cache the error. This overrides the default
|
||||||
|
// negative cache time.
|
||||||
|
type cachedError interface {
|
||||||
|
CacheFor() time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
func NewCachingMux() *CachingMux {
|
func NewCachingMux() *CachingMux {
|
||||||
return &CachingMux{
|
return &CachingMux{
|
||||||
Supervisor: suture.NewSimple("discover.cachingMux"),
|
Supervisor: suture.NewSimple("discover.cachingMux"),
|
||||||
@ -84,10 +91,11 @@ func (m *CachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, relays
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cacheEntry.found && time.Since(cacheEntry.when) < finder.negCacheTime {
|
valid := time.Now().Before(cacheEntry.validUntil) || time.Since(cacheEntry.when) < finder.negCacheTime
|
||||||
|
if !cacheEntry.found && valid {
|
||||||
// It's a negative, valid entry. We should not make another
|
// It's a negative, valid entry. We should not make another
|
||||||
// attempt right now.
|
// attempt right now.
|
||||||
l.Debugln("negative cache entry for", deviceID, "at", finder)
|
l.Debugln("negative cache entry for", deviceID, "at", finder, "valid until", cacheEntry.when.Add(finder.negCacheTime), "or", cacheEntry.validUntil)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +119,14 @@ func (m *CachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, relays
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Lookup returned error, add a negative cache entry.
|
// Lookup returned error, add a negative cache entry.
|
||||||
m.caches[i].Set(deviceID, CacheEntry{
|
entry := CacheEntry{
|
||||||
when: time.Now(),
|
when: time.Now(),
|
||||||
found: false,
|
found: false,
|
||||||
})
|
}
|
||||||
|
if err, ok := err.(cachedError); ok {
|
||||||
|
entry.validUntil = time.Now().Add(err.CacheFor())
|
||||||
|
}
|
||||||
|
m.caches[i].Set(deviceID, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.mut.Unlock()
|
m.mut.Unlock()
|
||||||
|
@ -22,10 +22,11 @@ type Finder interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CacheEntry struct {
|
type CacheEntry struct {
|
||||||
Direct []string `json:"direct"`
|
Direct []string `json:"direct"`
|
||||||
Relays []Relay `json:"relays"`
|
Relays []Relay `json:"relays"`
|
||||||
when time.Time // When did we get the result
|
when time.Time // When did we get the result
|
||||||
found bool // Is it a success (cacheTime applies) or a failure (negCacheTime applies)?
|
found bool // Is it a success (cacheTime applies) or a failure (negCacheTime applies)?
|
||||||
|
validUntil time.Time // Validity time, overrides normal calculation
|
||||||
}
|
}
|
||||||
|
|
||||||
// A FinderService is a Finder that has background activity and must be run as
|
// A FinderService is a Finder that has background activity and must be run as
|
||||||
|
@ -56,6 +56,16 @@ type serverOptions struct {
|
|||||||
id string // expected server device ID
|
id string // expected server device ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A lookupError is any other error but with a cache validity time attached.
|
||||||
|
type lookupError struct {
|
||||||
|
error
|
||||||
|
cacheFor time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e lookupError) CacheFor() time.Duration {
|
||||||
|
return e.cacheFor
|
||||||
|
}
|
||||||
|
|
||||||
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, relayStat RelayStatusProvider) (FinderService, error) {
|
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, relayStat RelayStatusProvider) (FinderService, error) {
|
||||||
server, opts, err := parseOptions(server)
|
server, opts, err := parseOptions(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -138,11 +148,16 @@ func (c *globalClient) Lookup(device protocol.DeviceID) (direct []string, relays
|
|||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
l.Debugln("globalClient.Lookup", qURL, resp.Status)
|
l.Debugln("globalClient.Lookup", qURL, resp.Status)
|
||||||
return nil, nil, errors.New(resp.Status)
|
err := errors.New(resp.Status)
|
||||||
|
if secs, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil && secs > 0 {
|
||||||
|
err = lookupError{
|
||||||
|
error: err,
|
||||||
|
cacheFor: time.Duration(secs) * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle 429 and Retry-After?
|
|
||||||
|
|
||||||
var ann announcement
|
var ann announcement
|
||||||
err = json.NewDecoder(resp.Body).Decode(&ann)
|
err = json.NewDecoder(resp.Body).Decode(&ann)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
|
Loading…
Reference in New Issue
Block a user