Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4597142

Browse files
authored
feat: set default workspace proxy based on latency (#17812)
Auto select the proxy on first load (stored in local storage, so perbrowser), then defer to user selection. The auto selected proxy will notupdate again once set.
1 parent80b7947 commit4597142

File tree

7 files changed

+82
-12
lines changed

7 files changed

+82
-12
lines changed

‎site/src/contexts/ProxyContext.test.tsx

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ import type * as ProxyLatency from "./useProxyLatency";
2626
// here and not inside a unit test.
2727
jest.mock("contexts/useProxyLatency",()=>({
2828
useProxyLatency:()=>{
29-
return{proxyLatencies:hardCodedLatencies,refetch:jest.fn()};
29+
return{
30+
proxyLatencies:hardCodedLatencies,
31+
refetch:jest.fn(),
32+
loaded:true,
33+
};
3034
},
3135
}));
3236

@@ -115,7 +119,7 @@ describe("ProxyContextGetURLs", () => {
115119
preferredPathAppURL,
116120
preferredWildcardHostname,
117121
)=>{
118-
constpreferred=getPreferredProxy(regions,selected,latencies);
122+
constpreferred=getPreferredProxy(regions,selected,latencies,true);
119123
expect(preferred.preferredPathAppURL).toBe(preferredPathAppURL);
120124
expect(preferred.preferredWildcardHostname).toBe(
121125
preferredWildcardHostname,
@@ -138,10 +142,22 @@ const TestingComponent = () => {
138142

139143
// TestingScreen just mounts some components that we can check in the unit test.
140144
constTestingScreen=()=>{
141-
const{ proxy, userProxy, isFetched, isLoading, clearProxy, setProxy}=
142-
useProxy();
145+
const{
146+
proxy,
147+
userProxy,
148+
isFetched,
149+
isLoading,
150+
latenciesLoaded,
151+
clearProxy,
152+
setProxy,
153+
}=useProxy();
154+
143155
return(
144156
<>
157+
<div
158+
data-testid="latenciesLoaded"
159+
title={latenciesLoaded.toString()}
160+
></div>
145161
<divdata-testid="isFetched"title={isFetched.toString()}></div>
146162
<divdata-testid="isLoading"title={isLoading.toString()}></div>
147163
<divdata-testid="preferredProxy"title={proxy.proxy?.id}></div>
@@ -206,7 +222,6 @@ describe("ProxyContextSelection", () => {
206222
};
207223

208224
it.each([
209-
// Not latency behavior
210225
[
211226
"empty",
212227
{
@@ -220,6 +235,7 @@ describe("ProxyContextSelection", () => {
220235
"regions_no_selection",
221236
{
222237
expProxyID:MockPrimaryWorkspaceProxy.id,
238+
expUserProxyID:MockPrimaryWorkspaceProxy.id,
223239
regions:MockWorkspaceProxies,
224240
storageProxy:undefined,
225241
},
@@ -261,11 +277,12 @@ describe("ProxyContextSelection", () => {
261277
expUserProxyID:MockHealthyWildWorkspaceProxy.id,
262278
},
263279
],
264-
//Latency behavior is disabled, so theprimary should be selected.
280+
//First page load defers to theproxy by latency
265281
[
266282
"regions_default_low_latency",
267283
{
268-
expProxyID:MockPrimaryWorkspaceProxy.id,
284+
expProxyID:MockHealthyWildWorkspaceProxy.id,
285+
expUserProxyID:MockHealthyWildWorkspaceProxy.id,
269286
regions:MockWorkspaceProxies,
270287
storageProxy:undefined,
271288
latencies:{
@@ -362,6 +379,10 @@ describe("ProxyContextSelection", () => {
362379
TestingComponent();
363380
awaitwaitForLoaderToBeRemoved();
364381

382+
awaitscreen.findByTestId("latenciesLoaded").then((x)=>{
383+
expect(x.title).toBe("true");
384+
});
385+
365386
if(afterLoad){
366387
awaitafterLoad();
367388
}

‎site/src/contexts/ProxyContext.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ export interface ProxyContextValue {
5454
// then the latency has not been fetched yet. Calculations happen async for each proxy in the list.
5555
// Refer to the returned report for a given proxy for more information.
5656
proxyLatencies:ProxyLatencies;
57+
// latenciesLoaded is true when the latencies have been initially loaded.
58+
// Once set to true, it will not be set to false again.
59+
latenciesLoaded:boolean;
5760
// refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies
5861
// are loaded once.
5962
refetchProxyLatencies:()=>Date;
@@ -122,8 +125,11 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
122125

123126
// Every time we get a new proxiesResponse, update the latency check
124127
// to each workspace proxy.
125-
const{ proxyLatencies,refetch:refetchProxyLatencies}=
126-
useProxyLatency(proxiesResp);
128+
const{
129+
proxyLatencies,
130+
refetch:refetchProxyLatencies,
131+
loaded:latenciesLoaded,
132+
}=useProxyLatency(proxiesResp);
127133

128134
// updateProxy is a helper function that when called will
129135
// update the proxy being used.
@@ -136,7 +142,8 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
136142
loadUserSelectedProxy(),
137143
proxyLatencies,
138144
// Do not auto select based on latencies, as inconsistent latencies can cause this
139-
// to behave poorly.
145+
// to change on each call. updateProxy should be stable when selecting a proxy to
146+
// prevent flickering.
140147
false,
141148
),
142149
);
@@ -149,6 +156,34 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
149156
updateProxy();
150157
},[proxiesResp,proxyLatencies]);
151158

159+
// This useEffect will auto select the best proxy if the user has not selected one.
160+
// It must wait until all latencies are loaded to select based on latency. This does mean
161+
// the first time a user loads the page, the proxy will "flicker" to the best proxy.
162+
//
163+
// Once the page is loaded, or the user selects a proxy, this will not run again.
164+
// biome-ignore lint/correctness/useExhaustiveDependencies: Only update if the source data changes
165+
useEffect(()=>{
166+
if(loadUserSelectedProxy()!==undefined){
167+
return;// User has selected a proxy, do not auto select.
168+
}
169+
if(!latenciesLoaded){
170+
// Wait until the latencies are loaded first.
171+
return;
172+
}
173+
174+
constbest=getPreferredProxy(
175+
proxiesResp??[],
176+
loadUserSelectedProxy(),
177+
proxyLatencies,
178+
true,
179+
);
180+
181+
if(best?.proxy){
182+
saveUserSelectedProxy(best.proxy);
183+
updateProxy();
184+
}
185+
},[latenciesLoaded,proxiesResp,proxyLatencies]);
186+
152187
return(
153188
<ProxyContext.Provider
154189
value={{
@@ -157,6 +192,7 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
157192
userProxy:userSavedProxy,
158193
proxy:proxy,
159194
proxies:proxiesResp,
195+
latenciesLoaded:latenciesLoaded,
160196
isLoading:proxiesLoading,
161197
isFetched:proxiesFetched,
162198
error:proxiesError,
@@ -214,12 +250,12 @@ export const getPreferredProxy = (
214250

215251
// If no proxy is selected, or the selected proxy is unhealthy default to the primary proxy.
216252
if(!selectedProxy||!selectedProxy.healthy){
217-
//By default, usethe primary proxy.
253+
//Default tothe primary proxy
218254
selectedProxy=proxies.find((proxy)=>proxy.name==="primary");
219255

220256
// If we have latencies, then attempt to use the best proxy by latency instead.
221257
constbest=selectByLatency(proxies,latencies);
222-
if(autoSelectBasedOnLatency&&best){
258+
if(autoSelectBasedOnLatency&&best!==undefined){
223259
selectedProxy=best;
224260
}
225261
}

‎site/src/contexts/useProxyLatency.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ export const useProxyLatency = (
4848
// Until the new values are loaded, the old values will still be used.
4949
refetch:()=>Date;
5050
proxyLatencies:Record<string,ProxyLatencyReport>;
51+
// loaded signals all latency requests have completed. Once set to true, this will not change.
52+
// Latencies at this point should be loaded from local storage, and updated asynchronously as needed.
53+
// If local storage has updated latencies, then this will be set to true with 0 actual network requests.
54+
// The loaded latencies will all be from the cache.
55+
loaded:boolean;
5156
}=>{
5257
// maxStoredLatencies is the maximum number of latencies to store per proxy in local storage.
5358
letmaxStoredLatencies=1;
@@ -73,6 +78,8 @@ export const useProxyLatency = (
7378
newDate(newDate().getTime()-proxyIntervalSeconds*1000).toISOString(),
7479
);
7580

81+
const[loaded,setLoaded]=useState(false);
82+
7683
// Refetch will always set the latestFetchRequest to the current time, making all the cached latencies
7784
// stale and triggering a refetch of all proxies in the list.
7885
constrefetch=()=>{
@@ -231,6 +238,7 @@ export const useProxyLatency = (
231238

232239
// Local storage cleanup
233240
garbageCollectStoredLatencies(proxies,maxStoredLatencies);
241+
setLoaded(true);
234242
});
235243

236244
return()=>{
@@ -241,6 +249,7 @@ export const useProxyLatency = (
241249
return{
242250
proxyLatencies,
243251
refetch,
252+
loaded,
244253
};
245254
};
246255

‎site/src/modules/dashboard/Navbar/MobileMenu.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const meta: Meta<typeof MobileMenu> = {
2323
component:MobileMenu,
2424
args:{
2525
proxyContextValue:{
26+
latenciesLoaded:true,
2627
proxy:{
2728
preferredPathAppURL:"",
2829
preferredWildcardHostname:"",

‎site/src/modules/dashboard/Navbar/NavbarView.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { renderWithAuth } from "testHelpers/renderHelpers";
66
import{NavbarView}from"./NavbarView";
77

88
constproxyContextValue:ProxyContextValue={
9+
latenciesLoaded:true,
910
proxy:{
1011
preferredPathAppURL:"",
1112
preferredWildcardHostname:"",

‎site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { withDesktopViewport } from "testHelpers/storybook";
1515
import{ProxyMenu}from"./ProxyMenu";
1616

1717
constdefaultProxyContextValue={
18+
latenciesLoaded:true,
1819
proxyLatencies:MockProxyLatencies,
1920
proxy:getPreferredProxy(MockWorkspaceProxies,undefined),
2021
proxies:MockWorkspaceProxies,

‎site/src/testHelpers/storybook.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ export const withProxyProvider =
167167
return(
168168
<ProxyContext.Provider
169169
value={{
170+
latenciesLoaded:true,
170171
proxyLatencies:MockProxyLatencies,
171172
proxy:getPreferredProxy([],undefined),
172173
proxies:[],

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp