Fix unnecessary /versions calls (#7747)

- Fixes https://github.com/enso-org/cloud-v2/issues/659

`getProjectDetails` was calling `listVersions` to get a fallback IDE version, creating a lot of unnecessary requests to the backend, *especially* because `getProjectDetails` is called periodically when a project is opening.

In this PR, the implementation has been changed to cache the fallback version for one day, meaning the extra `listVersions` calls should now only ever happen once per client per day.

# Important Notes
None
This commit is contained in:
somebody1234 2023-09-07 22:59:02 +10:00 committed by GitHub
parent 9b0f551881
commit 2155daa935
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -20,6 +20,9 @@ const STATUS_SUCCESS_LAST = 299
/** HTTP status indicating that the server encountered a fatal exception. */
const STATUS_SERVER_ERROR = 500
/** The number of milliseconds in one day. */
const ONE_DAY_MS = 86_400_000
/** Default HTTP body for an "open project" request. */
const DEFAULT_OPEN_PROJECT_BODY: backendModule.OpenProjectRequestBody = {
forceCreate: false,
@ -194,9 +197,16 @@ interface ListVersionsResponseBody {
// === RemoteBackend ===
// =====================
/** Information for a cached default version. */
interface DefaultVersionInfo {
version: backendModule.VersionNumber
lastUpdatedEpochMs: number
}
/** Class for sending requests to the Cloud backend API endpoints. */
export class RemoteBackend extends backendModule.Backend {
readonly type = backendModule.BackendType.remote
protected defaultVersions: Partial<Record<backendModule.VersionType, DefaultVersionInfo>> = {}
/** Create a new instance of the {@link RemoteBackend} API client.
*
@ -471,29 +481,19 @@ export class RemoteBackend extends backendModule.Backend {
} else {
const project = await response.json()
const ideVersion =
project.ide_version ??
(
await this.listVersions({
versionType: backendModule.VersionType.ide,
default: true,
})
)[0]?.number
if (ideVersion == null) {
return this.throw('No IDE version found')
} else {
return {
...project,
ideVersion,
engineVersion: project.engine_version,
jsonAddress:
project.address != null
? backendModule.Address(`${project.address}json`)
: null,
binaryAddress:
project.address != null
? backendModule.Address(`${project.address}binary`)
: null,
}
project.ide_version ?? (await this.getDefaultVersion(backendModule.VersionType.ide))
return {
...project,
ideVersion,
engineVersion: project.engine_version,
jsonAddress:
project.address != null
? backendModule.Address(`${project.address}json`)
: null,
binaryAddress:
project.address != null
? backendModule.Address(`${project.address}binary`)
: null,
}
}
}
@ -775,6 +775,32 @@ export class RemoteBackend extends backendModule.Backend {
}
}
/** Get the default version given the type of version (IDE or backend). */
protected async getDefaultVersion(versionType: backendModule.VersionType) {
const cached = this.defaultVersions[versionType]
const nowEpochMs = Number(new Date())
if (cached != null && nowEpochMs - cached.lastUpdatedEpochMs < ONE_DAY_MS) {
return cached.version
} else {
const version = (
await this.listVersions({
versionType,
default: true,
})
)[0]?.number
if (version == null) {
throw new Error(`No default ${versionType} version found.`)
} else {
const info: DefaultVersionInfo = {
version,
lastUpdatedEpochMs: nowEpochMs,
}
this.defaultVersions[versionType] = info
return info.version
}
}
}
/** Send an HTTP GET request to the given path. */
private get<T = void>(path: string) {
return this.client.get<T>(`${config.ACTIVE_CONFIG.apiUrl}/${path}`)