feat: fetch proxy latencies at most once per 30s (#8277)

* feat: fetch proxy latencies at most once per 30s
This commit is contained in:
Steven Masley
2023-06-30 12:45:02 -04:00
committed by GitHub
parent f0bd258ff1
commit eb0497ff82
+42 -2
View File
@@ -4,6 +4,8 @@ import PerformanceObserver from "@fastly/performance-observer-polyfill"
import axios from "axios"
import { generateRandomString } from "utils/random"
const proxyIntervalSeconds = 30 // seconds
export interface ProxyLatencyReport {
// accurate identifies if the latency was calculated using the
// PerformanceResourceTiming API. If this is false, then the
@@ -17,6 +19,8 @@ export interface ProxyLatencyReport {
interface ProxyLatencyAction {
proxyID: string
// cached indicates if the latency was loaded from a cache (local storage)
cached: boolean
report: ProxyLatencyReport
}
@@ -59,8 +63,13 @@ export const useProxyLatency = (
// This latestFetchRequest is used to trigger a refetch of the proxy latencies.
const [latestFetchRequest, setLatestFetchRequest] = useState(
new Date().toISOString(),
// The initial state is the current time minus the interval. Any proxies that have a latency after this
// in the cache are still valid.
new Date(new Date().getTime() - proxyIntervalSeconds * 1000).toISOString(),
)
// Refetch will always set the latestFetchRequest to the current time, making all the cached latencies
// stale and triggering a refetch of all proxies in the list.
const refetch = () => {
const d = new Date()
setLatestFetchRequest(d.toISOString())
@@ -73,6 +82,8 @@ export const useProxyLatency = (
return
}
const storedLatencies = loadStoredLatencies()
// proxyMap is a map of the proxy path_app_url to the proxy object.
// This is for the observer to know which requests are important to
// record.
@@ -82,6 +93,28 @@ export const useProxyLatency = (
return acc
}
// Do not run latency checks if a cached check exists below the latestFetchRequest Date.
// This prevents fetching latencies too often.
// 1. Fetch the latest stored latency for the given proxy.
// 2. If the latest latency is after the latestFetchRequest, then skip the latency check.
if (storedLatencies && storedLatencies[proxy.id]) {
const fetchRequestDate = new Date(latestFetchRequest)
const latest = storedLatencies[proxy.id].reduce((prev, next) =>
prev.at > next.at ? prev : next,
)
if (latest && latest.at > fetchRequestDate) {
// dispatch the cached latency. This latency already went through the
// guard logic below, so we can just dispatch it again directly.
dispatchProxyLatencies({
proxyID: proxy.id,
cached: true,
report: latest,
})
return acc
}
}
// Add a random query param to the url to make sure we don't get a cached response.
// This is important in case there is some caching layer between us and the proxy.
const url = new URL(
@@ -131,6 +164,7 @@ export const useProxyLatency = (
}
const update = {
proxyID: check.id,
cached: false,
report: {
latencyMS,
accurate,
@@ -203,7 +237,13 @@ const loadStoredLatencies = (): Record<string, ProxyLatencyReport[]> => {
return {}
}
return JSON.parse(str)
return JSON.parse(str, (key, value) => {
// By default json loads dates as strings. We want to convert them back to 'Date's.
if (key === "at") {
return new Date(value)
}
return value
})
}
const updateStoredLatencies = (action: ProxyLatencyAction): void => {