Fix throughputcap check (#1156)

This commit is contained in:
victor-meng
2021-11-05 10:23:21 -07:00
committed by GitHub
parent 5597a1e8b6
commit a3d88af175
9 changed files with 72 additions and 26 deletions

View File

@@ -27,6 +27,7 @@ export interface DatabaseAccountExtendedProperties {
ipRules?: IpRule[]; ipRules?: IpRule[];
privateEndpointConnections?: unknown[]; privateEndpointConnections?: unknown[];
capacity?: { totalThroughputLimit: number }; capacity?: { totalThroughputLimit: number };
locations?: DatabaseAccountResponseLocation[];
} }
export interface DatabaseAccountResponseLocation { export interface DatabaseAccountResponseLocation {

View File

@@ -213,20 +213,9 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
}, },
}; };
this.totalThroughputUsed = 0; if (userContext.databaseAccount?.properties.capacity?.totalThroughputLimit) {
(useDatabases.getState().databases || []).forEach((database) => { this.calculateTotalThroughputUsed();
if (database.offer()) {
const dbThroughput = database.offer().autoscaleMaxThroughput || database.offer().manualThroughput;
this.totalThroughputUsed += dbThroughput;
} }
(database.collections() || []).forEach((collection) => {
if (collection.offer()) {
const colThroughput = collection.offer().autoscaleMaxThroughput || collection.offer().manualThroughput;
this.totalThroughputUsed += colThroughput;
}
});
});
} }
componentDidMount(): void { componentDidMount(): void {
@@ -504,6 +493,26 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onMongoIndexingPolicyDiscardableChange = (isMongoIndexingPolicyDiscardable: boolean): void => private onMongoIndexingPolicyDiscardableChange = (isMongoIndexingPolicyDiscardable: boolean): void =>
this.setState({ isMongoIndexingPolicyDiscardable }); this.setState({ isMongoIndexingPolicyDiscardable });
private calculateTotalThroughputUsed = (): void => {
this.totalThroughputUsed = 0;
(useDatabases.getState().databases || []).forEach(async (database) => {
if (database.offer()) {
const dbThroughput = database.offer().autoscaleMaxThroughput || database.offer().manualThroughput;
this.totalThroughputUsed += dbThroughput;
}
(database.collections() || []).forEach(async (collection) => {
if (collection.offer()) {
const colThroughput = collection.offer().autoscaleMaxThroughput || collection.offer().manualThroughput;
this.totalThroughputUsed += colThroughput;
}
});
});
const numberOfRegions = userContext.databaseAccount?.properties.locations?.length || 1;
this.totalThroughputUsed *= numberOfRegions;
};
public getAnalyticalStorageTtl = (): number => { public getAnalyticalStorageTtl = (): number => {
if (this.isAnalyticalStorageEnabled) { if (this.isAnalyticalStorageEnabled) {
if (this.state.analyticalStorageTtlSelection === TtlType.On) { if (this.state.analyticalStorageTtlSelection === TtlType.On) {
@@ -669,9 +678,11 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onMaxAutoPilotThroughputChange = (newThroughput: number): void => { private onMaxAutoPilotThroughputChange = (newThroughput: number): void => {
let throughputError = ""; let throughputError = "";
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit; const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
if (throughputCap && throughputCap - this.totalThroughputUsed < newThroughput - this.offer.autoscaleMaxThroughput) { const numberOfRegions = userContext.databaseAccount?.properties.locations?.length || 1;
const throughputDelta = (newThroughput - this.offer.autoscaleMaxThroughput) * numberOfRegions;
if (throughputCap && throughputCap - this.totalThroughputUsed < throughputDelta) {
throughputError = `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${ throughputError = `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${
this.totalThroughputUsed + newThroughput this.totalThroughputUsed + throughputDelta
} RU/s. Change total throughput limit in cost management.`; } RU/s. Change total throughput limit in cost management.`;
} }
this.setState({ autoPilotThroughput: newThroughput, throughputError }); this.setState({ autoPilotThroughput: newThroughput, throughputError });
@@ -680,9 +691,11 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onThroughputChange = (newThroughput: number): void => { private onThroughputChange = (newThroughput: number): void => {
let throughputError = ""; let throughputError = "";
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit; const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
const numberOfRegions = userContext.databaseAccount?.properties.locations?.length || 1;
const throughputDelta = (newThroughput - this.offer.manualThroughput) * numberOfRegions;
if (throughputCap && throughputCap - this.totalThroughputUsed < newThroughput - this.offer.manualThroughput) { if (throughputCap && throughputCap - this.totalThroughputUsed < newThroughput - this.offer.manualThroughput) {
throughputError = `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${ throughputError = `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${
this.totalThroughputUsed + newThroughput this.totalThroughputUsed + throughputDelta
} RU/s. Change total throughput limit in cost management.`; } RU/s. Change total throughput limit in cost management.`;
} }
this.setState({ throughput: newThroughput, throughputError }); this.setState({ throughput: newThroughput, throughputError });

View File

@@ -40,6 +40,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
setThroughputValue(throughput); setThroughputValue(throughput);
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit; const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
const numberOfRegions = userContext.databaseAccount?.properties.locations?.length || 1;
useEffect(() => { useEffect(() => {
// throughput cap check for the initial state // throughput cap check for the initial state
@@ -57,12 +58,13 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
} }
}); });
}); });
totalThroughput *= numberOfRegions;
setTotalThroughputUsed(totalThroughput); setTotalThroughputUsed(totalThroughput);
if (throughputCap && throughputCap - totalThroughput < throughput) { if (throughputCap && throughputCap - totalThroughput < throughput) {
setThroughputError( setThroughputError(
`Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${ `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${
totalThroughputUsed + throughput totalThroughput + throughput * numberOfRegions
} RU/s. Change total throughput limit in cost management.` } RU/s. Change total throughput limit in cost management.`
); );
@@ -74,7 +76,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
if (throughputCap && throughputCap - totalThroughputUsed < newThroughput) { if (throughputCap && throughputCap - totalThroughputUsed < newThroughput) {
setThroughputError( setThroughputError(
`Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${ `Your account is currently configured with a total throughput limit of ${throughputCap} RU/s. This update isn't possible because it would increase the total throughput to ${
totalThroughputUsed + newThroughput totalThroughputUsed + newThroughput * numberOfRegions
} RU/s. Change total throughput limit in cost management.` } RU/s. Change total throughput limit in cost management.`
); );
setIsThroughputCapExceeded(true); setIsThroughputCapExceeded(true);

View File

@@ -1176,7 +1176,9 @@ export default class Explorer {
<CassandraAddCollectionPane explorer={this} cassandraApiClient={new CassandraAPIDataClient()} /> <CassandraAddCollectionPane explorer={this} cassandraApiClient={new CassandraAPIDataClient()} />
); );
} else { } else {
await useDatabases.getState().loadDatabaseOffers(); userContext.databaseAccount?.properties.capacity?.totalThroughputLimit
? await useDatabases.getState().loadAllOffers()
: await useDatabases.getState().loadDatabaseOffers();
useSidePanel useSidePanel
.getState() .getState()
.openSidePanel("New " + getCollectionName(), <AddCollectionPanel explorer={this} databaseId={databaseId} />); .openSidePanel("New " + getCollectionName(), <AddCollectionPanel explorer={this} databaseId={databaseId} />);

View File

@@ -308,8 +308,12 @@ function createNewDatabase(container: Explorer): CommandButtonComponentProps {
return { return {
iconSrc: AddDatabaseIcon, iconSrc: AddDatabaseIcon,
iconAlt: label, iconAlt: label,
onCommandClick: () => onCommandClick: async () => {
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />), if (userContext.databaseAccount?.properties.capacity?.totalThroughputLimit) {
await useDatabases.getState().loadAllOffers();
}
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />);
},
commandButtonLabel: label, commandButtonLabel: label,
ariaLabel: label, ariaLabel: label,
hasPopup: true, hasPopup: true,

View File

@@ -307,10 +307,14 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
iconSrc: AddDatabaseIcon, iconSrc: AddDatabaseIcon,
title: "New " + getDatabaseName(), title: "New " + getDatabaseName(),
description: undefined, description: undefined,
onClick: () => onClick: async () => {
if (userContext.databaseAccount?.properties.capacity?.totalThroughputLimit) {
await useDatabases.getState().loadAllOffers();
}
useSidePanel useSidePanel
.getState() .getState()
.openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this.container} />), .openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={this.container} />);
},
}); });
} }

View File

@@ -576,7 +576,9 @@ export default class Collection implements ViewModels.Collection {
public onSettingsClick = async (): Promise<void> => { public onSettingsClick = async (): Promise<void> => {
useSelectedNode.getState().setSelectedNode(this); useSelectedNode.getState().setSelectedNode(this);
await this.loadOffer(); userContext.databaseAccount?.properties.capacity?.totalThroughputLimit
? await useDatabases.getState().loadAllOffers()
: await this.loadOffer();
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Settings); this.selectedSubnodeKind(ViewModels.CollectionTabKind.Settings);
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, { TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
description: "Settings node", description: "Settings node",

View File

@@ -57,7 +57,7 @@ export default class Database implements ViewModels.Database {
this.isOfferRead = false; this.isOfferRead = false;
} }
public onSettingsClick = (): void => { public onSettingsClick = async (): Promise<void> => {
useSelectedNode.getState().setSelectedNode(this); useSelectedNode.getState().setSelectedNode(this);
this.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings); this.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings);
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, { TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
@@ -66,6 +66,10 @@ export default class Database implements ViewModels.Database {
dataExplorerArea: Constants.Areas.ResourceTree, dataExplorerArea: Constants.Areas.ResourceTree,
}); });
if (userContext.databaseAccount?.properties.capacity?.totalThroughputLimit) {
await useDatabases.getState().loadAllOffers();
}
const pendingNotificationsPromise: Promise<DataModels.Notification> = this.getPendingThroughputSplitNotification(); const pendingNotificationsPromise: Promise<DataModels.Notification> = this.getPendingThroughputSplitNotification();
const tabKind = ViewModels.CollectionTabKind.DatabaseSettingsV2; const tabKind = ViewModels.CollectionTabKind.DatabaseSettingsV2;
const matchingTabs = useTabs.getState().getTabs(tabKind, (tab) => tab.node?.id() === this.id()); const matchingTabs = useTabs.getState().getTabs(tabKind, (tab) => tab.node?.id() === this.id());

View File

@@ -18,6 +18,7 @@ interface DatabasesState {
findCollection: (databaseId: string, collectionId: string) => ViewModels.Collection; findCollection: (databaseId: string, collectionId: string) => ViewModels.Collection;
isLastCollection: () => boolean; isLastCollection: () => boolean;
loadDatabaseOffers: () => Promise<void>; loadDatabaseOffers: () => Promise<void>;
loadAllOffers: () => Promise<void>;
isFirstResourceCreated: () => boolean; isFirstResourceCreated: () => boolean;
findSelectedDatabase: () => ViewModels.Database; findSelectedDatabase: () => ViewModels.Database;
validateDatabaseId: (id: string) => boolean; validateDatabaseId: (id: string) => boolean;
@@ -97,6 +98,19 @@ export const useDatabases: UseStore<DatabasesState> = create((set, get) => ({
}) })
); );
}, },
loadAllOffers: async () => {
await Promise.all(
get().databases?.map(async (database: ViewModels.Database) => {
await database.loadOffer();
await database.loadCollections();
await Promise.all(
(database.collections() || []).map(async (collection: ViewModels.Collection) => {
await collection.loadOffer();
})
);
})
);
},
isFirstResourceCreated: () => { isFirstResourceCreated: () => {
const databases = get().databases; const databases = get().databases;