-
Notifications
You must be signed in to change notification settings - Fork 175
failover: retry the same host when no fallback region exists, and cover the Cloud API hosts #1002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+112
−5
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -69,15 +69,22 @@ type failoverConfig struct { | |||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // attempts returns the total request attempts for a host; 1 means no failover. | ||||||||||||||||
| // Failover engages only when enabled and the host is a LiveKit Cloud domain | ||||||||||||||||
| // (or force is set). | ||||||||||||||||
| // Failover engages only when enabled and the host is a LiveKit Cloud project | ||||||||||||||||
| // or Cloud API domain (or force is set). | ||||||||||||||||
| func (c failoverConfig) attempts(hostname string) int { | ||||||||||||||||
| if c.enabled && (c.force || isCloud(hostname)) { | ||||||||||||||||
| if c.enabled && (c.force || isCloud(hostname) || isCloudAPI(hostname)) { | ||||||||||||||||
| return failoverMaxAttempts | ||||||||||||||||
| } | ||||||||||||||||
| return 1 | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| // isCloudAPI reports whether the hostname is a LiveKit Cloud API endpoint | ||||||||||||||||
| // (cloud-api.livekit.io or a cloud-api.<env>.livekit.io variant). | ||||||||||||||||
| func isCloudAPI(hostname string) bool { | ||||||||||||||||
| hostname = strings.ToLower(hostname) | ||||||||||||||||
| return strings.HasPrefix(hostname, "cloud-api.") && strings.HasSuffix(hostname, ".livekit.io") | ||||||||||||||||
|
devin-ai-integration[bot] marked this conversation as resolved.
|
||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+83
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Mixed-case Cloud API hosts lose retries A mixed-case Cloud API hostname makes
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||
|
|
||||||||||||||||
| type failoverEnabledKey struct{} | ||||||||||||||||
| type failoverForceKey struct{} | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -238,6 +245,8 @@ func (t *failoverTransport) failover(req *http.Request, maxAttempts int, timeout | |||||||||||||||
| scheme, host := req.URL.Scheme, req.URL.Host | ||||||||||||||||
| tried := map[string]struct{}{strings.ToLower(host): {}} | ||||||||||||||||
| var regions *livekit.RegionSettings // discovered lazily on the first failure | ||||||||||||||||
| // A Cloud API host has a single origin; region discovery is never consulted. | ||||||||||||||||
| discover := !isCloudAPI(req.URL.Hostname()) | ||||||||||||||||
|
|
||||||||||||||||
| var resp *http.Response | ||||||||||||||||
| var err error | ||||||||||||||||
|
|
@@ -259,13 +268,15 @@ func (t *failoverTransport) failover(req *http.Request, maxAttempts int, timeout | |||||||||||||||
| return terminate(resp, err, cancel) | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if regions == nil { | ||||||||||||||||
| if regions == nil && discover { | ||||||||||||||||
| u := url.URL{Scheme: req.URL.Scheme, Host: req.URL.Host, Path: "/settings/regions"} | ||||||||||||||||
| regions, _ = t.regions.get(req.URL.Host, u.String(), req.Header, 0) | ||||||||||||||||
| } | ||||||||||||||||
| nextScheme, nextHost, ok := nextRegion(regions, tried) | ||||||||||||||||
| if !ok { | ||||||||||||||||
| return terminate(resp, err, cancel) // no untried region left | ||||||||||||||||
| // With no fallback region, a retryable failure is retried against | ||||||||||||||||
| // the same host. | ||||||||||||||||
| nextScheme, nextHost = scheme, host | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| status := 0 | ||||||||||||||||
|
|
||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Cloud API failures trigger futile discovery
A retryable Cloud API failure runs unsupported region discovery before
failoverretries or returns. A nil result triggers discovery again after another transport error, adding up to four seconds.Learn more
Cloud project hosts use
/settings/regionsto choose another region. Cloud API hosts have one origin and return 404 from that endpoint. Enabling their failover enters the same discovery branch after every retryable response. A failed fetch leavesregionsnil, so the next transport failure fetches again. Each fetch uses the independent two-second region discovery timeout, outside the attempt timeout.Example: A dead Cloud API origin consumes a 10-second attempt, a 2-second discovery timeout, another 10-second attempt, and another 2-second discovery timeout before its final attempt. A fast 503 still waits for the unsupported discovery request before being returned.
Recommended fix: Skip
regionCache.getforisCloudAPI(req.URL.Hostname())and proceed directly to the same-host transport-error branch. Preserve immediate return for Cloud API 5xx responses.Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to avoid this call to regions?