Skip to content

Commit

Permalink
fix(manager): preload access keys before metrics (#2402)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellacosse authored Feb 24, 2025
1 parent 7fedaee commit ce6c77f
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 50 deletions.
79 changes: 79 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions server_manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@material/mwc-formfield": "^0.27.0",
"@material/mwc-icon": "^0.27.0",
"@material/mwc-icon-button": "^0.27.0",
"@material/mwc-linear-progress": "^0.27.0",
"@material/mwc-list": "^0.27.0",
"@material/mwc-menu": "^0.27.0",
"@material/mwc-radio": "^0.27.0",
Expand Down
122 changes: 72 additions & 50 deletions server_manager/www/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1034,10 +1034,19 @@ export class App {
serverView: ServerView
) {
try {
const [serverMetrics, serverAccessKeys] = await Promise.all([
selectedServer.getServerMetrics(),
selectedServer.listAccessKeys(),
]);
const serverAccessKeysPromise = selectedServer.listAccessKeys();
const serverMetricsPromise = selectedServer.getServerMetrics();

// Preload an incomplete access key table UI based on the much faster list access key endpoint:
const serverAccessKeys = await serverAccessKeysPromise;

// (only do this if there's currently no data at all)
if (!serverView.hasAccessKeyData) {
this.refreshAccessKeyTableUI(serverView, serverAccessKeys);
}

// Now load the full server metrics object (slow):
const serverMetrics = await serverMetricsPromise;

if (!serverMetrics.server) {
serverView.serverMetricsData = {
Expand Down Expand Up @@ -1091,58 +1100,22 @@ export class App {
}));
}

serverView.hasServerMetricsData = true;
// Join the server metrics data with the previous access key information
// now that we've populated the accessKeyMetricsIndex:
const accessKeyMetricsIndex: Map<string, server_model.AccessKeyMetrics> =
new Map();

const accessKeyMetricsIndex = new Map<
string,
server_model.AccessKeyMetrics
>();
for (const accessKey of serverMetrics.accessKeys) {
accessKeyMetricsIndex.set(accessKey.accessKeyId, accessKey);
}

serverView.accessKeyData = serverAccessKeys.map(accessKey => {
const accessKeyMetrics = accessKeyMetricsIndex.get(accessKey.id);

const resolveKeyName = (key: server_model.AccessKey) =>
key.name || this.appRoot.localize('key', 'keyId', key.id);

let dataLimit = accessKey.dataLimit;
if (!dataLimit && serverView.isDefaultDataLimitEnabled) {
dataLimit = {
bytes: serverView.defaultDataLimitBytes,
};
}

if (!accessKeyMetrics) {
return {
...accessKey,
name: resolveKeyName(accessKey),
isOnline: false,
dataTransferred: {
bytes: 0,
},
dataLimit,
};
}

let isOnline = false;
if (accessKeyMetrics.connection) {
isOnline =
accessKeyMetrics.connection.lastTrafficSeen >=
new Date(Date.now() - 5 * MINUTES_TO_MILLISECONDS);
}

return {
...accessKey,
...accessKeyMetrics,
name: resolveKeyName(accessKey),
isOnline,
dataLimit,
};
});
this.refreshAccessKeyTableUI(
serverView,
serverAccessKeys,
accessKeyMetricsIndex
);

serverView.hasAccessKeyData = true;
serverView.hasServerMetricsData = true;
} catch (e) {
// Since failures are invisible to users we generally want exceptions here to bubble
// up and trigger a Sentry report. The exception is network errors, about which we can't
Expand All @@ -1157,6 +1130,55 @@ export class App {
}
}

private refreshAccessKeyTableUI(
serverView: ServerView,
serverAccessKeys: server_model.AccessKey[],
accessKeyMetricsIndex?: Map<string, server_model.AccessKeyMetrics>
) {
serverView.accessKeyData = serverAccessKeys.map(accessKey => {
const accessKeyMetrics = accessKeyMetricsIndex?.get(accessKey.id);

const resolveKeyName = (key: server_model.AccessKey) =>
key.name || this.appRoot.localize('key', 'keyId', key.id);

let dataLimit = accessKey.dataLimit;
if (!dataLimit && serverView.isDefaultDataLimitEnabled) {
dataLimit = {
bytes: serverView.defaultDataLimitBytes,
};
}

if (!accessKeyMetrics) {
return {
...accessKey,
name: resolveKeyName(accessKey),
isOnline: false,
dataTransferred: {
bytes: 0,
},
dataLimit,
};
}

let isOnline = false;
if (accessKeyMetrics.connection) {
isOnline =
accessKeyMetrics.connection.lastTrafficSeen >=
new Date(Date.now() - 5 * MINUTES_TO_MILLISECONDS);
}

return {
...accessKey,
...accessKeyMetrics,
name: resolveKeyName(accessKey),
isOnline,
dataLimit,
};
});

serverView.hasAccessKeyData = true;
}

private countryCodeToEmoji(countryCode: string) {
if (!countryCode || !/^[A-Z]{2}$/.test(countryCode)) {
return '';
Expand Down
9 changes: 9 additions & 0 deletions server_manager/www/ui_components/outline-server-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import '@polymer/paper-menu-button/paper-menu-button';
import '@polymer/paper-progress/paper-progress';
import '@polymer/paper-tabs/paper-tabs';
import '@polymer/paper-tooltip/paper-tooltip';
import '@material/mwc-linear-progress';
import './cloud-install-styles';
import './outline-iconset';
import './outline-help-bubble';
Expand Down Expand Up @@ -281,6 +282,11 @@ export class ServerView extends DirMixin(PolymerElement) {
.metrics-loading-container {
background: hsl(197, 13%, 22%);
}
mwc-linear-progress {
--mdc-theme-primary: hsla(0, 0%, 46%, 1);
--mdc-linear-progress-buffer-color: var(--primary-green);
}
</style>
<div class="container">
Expand Down Expand Up @@ -448,6 +454,9 @@ export class ServerView extends DirMixin(PolymerElement) {
</aside>
<div class="connections-container">
<template is="dom-if" if="{{!hasServerMetricsData}}">
<mwc-linear-progress indeterminate></mwc-linear-progress>
</template>
<template is="dom-if" if="{{!hasAccessKeyData}}">
<div class="connections-loading-container">
<outline-progress-spinner></outline-progress-spinner>
Expand Down

0 comments on commit ce6c77f

Please sign in to comment.