mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-29 08:56:52 +00:00
Update autoscale throughput limits (#1229)
* Change minimum autoscale throughput and default autoscale throughput for free tier account to 1000 * Fix unit tests * Update snapshot * Fix cassandra add collection panel * Address comments * Add feature flag/flight * Remove console.log
This commit is contained in:
parent
7a809cd2bc
commit
605117c62d
@ -99,6 +99,7 @@ export class Flights {
|
|||||||
public static readonly PhoenixNotebooks = "phoenixnotebooks";
|
public static readonly PhoenixNotebooks = "phoenixnotebooks";
|
||||||
public static readonly PhoenixFeatures = "phoenixfeatures";
|
public static readonly PhoenixFeatures = "phoenixfeatures";
|
||||||
public static readonly NotebooksDownBanner = "notebooksdownbanner";
|
public static readonly NotebooksDownBanner = "notebooksdownbanner";
|
||||||
|
public static readonly FreeTierAutoscaleThroughput = "freetierautoscalethroughput";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AfecFeatures {
|
export class AfecFeatures {
|
||||||
|
@ -19,7 +19,7 @@ import { Action, ActionModifiers } from "../../../../../Shared/Telemetry/Telemet
|
|||||||
import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../../../../UserContext";
|
import { userContext } from "../../../../../UserContext";
|
||||||
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
||||||
import { minAutoPilotThroughput } from "../../../../../Utils/AutoPilotUtils";
|
import { autoPilotThroughput1K, autoPilotThroughput4K } from "../../../../../Utils/AutoPilotUtils";
|
||||||
import { calculateEstimateNumber, usageInGB } from "../../../../../Utils/PricingUtils";
|
import { calculateEstimateNumber, usageInGB } from "../../../../../Utils/PricingUtils";
|
||||||
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
||||||
import {
|
import {
|
||||||
@ -540,7 +540,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||||
value={this.overrideWithProvisionedThroughputSettings() ? "" : this.props.maxAutoPilotThroughput?.toString()}
|
value={this.overrideWithProvisionedThroughputSettings() ? "" : this.props.maxAutoPilotThroughput?.toString()}
|
||||||
onChange={this.onAutoPilotThroughputChange}
|
onChange={this.onAutoPilotThroughputChange}
|
||||||
min={minAutoPilotThroughput}
|
min={userContext.features.freetierAutoscaleThroughput ? autoPilotThroughput1K : autoPilotThroughput4K}
|
||||||
errorMessage={this.props.throughputError}
|
errorMessage={this.props.throughputError}
|
||||||
/>
|
/>
|
||||||
{!this.overrideWithProvisionedThroughputSettings() && this.getAutoPilotUsageCost()}
|
{!this.overrideWithProvisionedThroughputSettings() && this.getAutoPilotUsageCost()}
|
||||||
|
@ -5,6 +5,7 @@ const props = {
|
|||||||
isDatabase: false,
|
isDatabase: false,
|
||||||
showFreeTierExceedThroughputTooltip: true,
|
showFreeTierExceedThroughputTooltip: true,
|
||||||
isSharded: true,
|
isSharded: true,
|
||||||
|
isFreeTier: false,
|
||||||
setThroughputValue: () => jest.fn(),
|
setThroughputValue: () => jest.fn(),
|
||||||
setIsAutoscale: () => jest.fn(),
|
setIsAutoscale: () => jest.fn(),
|
||||||
setIsThroughputCapExceeded: () => jest.fn(),
|
setIsThroughputCapExceeded: () => jest.fn(),
|
||||||
|
@ -14,6 +14,7 @@ import "./ThroughputInput.less";
|
|||||||
export interface ThroughputInputProps {
|
export interface ThroughputInputProps {
|
||||||
isDatabase: boolean;
|
isDatabase: boolean;
|
||||||
isSharded: boolean;
|
isSharded: boolean;
|
||||||
|
isFreeTier: boolean;
|
||||||
showFreeTierExceedThroughputTooltip: boolean;
|
showFreeTierExceedThroughputTooltip: boolean;
|
||||||
setThroughputValue: (throughput: number) => void;
|
setThroughputValue: (throughput: number) => void;
|
||||||
setIsAutoscale: (isAutoscale: boolean) => void;
|
setIsAutoscale: (isAutoscale: boolean) => void;
|
||||||
@ -23,15 +24,20 @@ export interface ThroughputInputProps {
|
|||||||
|
|
||||||
export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||||
isDatabase,
|
isDatabase,
|
||||||
|
isSharded,
|
||||||
|
isFreeTier,
|
||||||
showFreeTierExceedThroughputTooltip,
|
showFreeTierExceedThroughputTooltip,
|
||||||
setThroughputValue,
|
setThroughputValue,
|
||||||
setIsAutoscale,
|
setIsAutoscale,
|
||||||
setIsThroughputCapExceeded,
|
setIsThroughputCapExceeded,
|
||||||
isSharded,
|
|
||||||
onCostAcknowledgeChange,
|
onCostAcknowledgeChange,
|
||||||
}: ThroughputInputProps) => {
|
}: ThroughputInputProps) => {
|
||||||
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
|
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
|
||||||
const [throughput, setThroughput] = useState<number>(AutoPilotUtils.minAutoPilotThroughput);
|
const [throughput, setThroughput] = useState<number>(
|
||||||
|
isFreeTier && userContext.features.freetierAutoscaleThroughput
|
||||||
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
|
: AutoPilotUtils.autoPilotThroughput4K
|
||||||
|
);
|
||||||
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
|
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
|
||||||
const [throughputError, setThroughputError] = useState<string>("");
|
const [throughputError, setThroughputError] = useState<string>("");
|
||||||
const [totalThroughputUsed, setTotalThroughputUsed] = useState<number>(0);
|
const [totalThroughputUsed, setTotalThroughputUsed] = useState<number>(0);
|
||||||
@ -151,11 +157,15 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
|
|
||||||
const handleOnChangeMode = (event: React.ChangeEvent<HTMLInputElement>, mode: string): void => {
|
const handleOnChangeMode = (event: React.ChangeEvent<HTMLInputElement>, mode: string): void => {
|
||||||
if (mode === "Autoscale") {
|
if (mode === "Autoscale") {
|
||||||
setThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
const defaultThroughput =
|
||||||
|
isFreeTier && userContext.features.freetierAutoscaleThroughput
|
||||||
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
|
: AutoPilotUtils.autoPilotThroughput4K;
|
||||||
|
setThroughput(defaultThroughput);
|
||||||
setIsAutoScaleSelected(true);
|
setIsAutoScaleSelected(true);
|
||||||
setThroughputValue(AutoPilotUtils.minAutoPilotThroughput);
|
setThroughputValue(defaultThroughput);
|
||||||
setIsAutoscale(true);
|
setIsAutoscale(true);
|
||||||
checkThroughputCap(AutoPilotUtils.minAutoPilotThroughput);
|
checkThroughputCap(defaultThroughput);
|
||||||
} else {
|
} else {
|
||||||
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
||||||
setIsAutoScaleSelected(false);
|
setIsAutoScaleSelected(false);
|
||||||
@ -226,7 +236,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
}}
|
}}
|
||||||
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||||
min={AutoPilotUtils.minAutoPilotThroughput}
|
min={
|
||||||
|
userContext.features.freetierAutoscaleThroughput
|
||||||
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
|
: AutoPilotUtils.autoPilotThroughput4K
|
||||||
|
}
|
||||||
value={throughput.toString()}
|
value={throughput.toString()}
|
||||||
aria-label="Max request units per second"
|
aria-label="Max request units per second"
|
||||||
required={true}
|
required={true}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
exports[`ThroughputInput Pane should render Default properly 1`] = `
|
exports[`ThroughputInput Pane should render Default properly 1`] = `
|
||||||
<ThroughputInput
|
<ThroughputInput
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
|
isFreeTier={false}
|
||||||
isSharded={true}
|
isSharded={true}
|
||||||
onCostAcknowledgeChange={[Function]}
|
onCostAcknowledgeChange={[Function]}
|
||||||
setIsAutoscale={[Function]}
|
setIsAutoscale={[Function]}
|
||||||
|
@ -249,6 +249,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
||||||
isDatabase={true}
|
isDatabase={true}
|
||||||
isSharded={this.state.isSharded}
|
isSharded={this.state.isSharded}
|
||||||
|
isFreeTier={this.isFreeTierAccount()}
|
||||||
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||||
@ -483,6 +484,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
isSharded={this.state.isSharded}
|
isSharded={this.state.isSharded}
|
||||||
|
isFreeTier={this.isFreeTierAccount()}
|
||||||
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||||
|
@ -146,9 +146,10 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
|||||||
// TODO add feature flag that disables validation for customers with custom accounts
|
// TODO add feature flag that disables validation for customers with custom accounts
|
||||||
if (isAutoscaleSelected) {
|
if (isAutoscaleSelected) {
|
||||||
if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) {
|
if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) {
|
||||||
setFormErrors(
|
const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput
|
||||||
`Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput`
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
);
|
: AutoPilotUtils.autoPilotThroughput4K;
|
||||||
|
setFormErrors(`Please enter a value greater than ${minAutoPilotThroughput} for autopilot throughput`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,6 +242,7 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
|||||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
||||||
isDatabase={true}
|
isDatabase={true}
|
||||||
isSharded={databaseCreateNewShared}
|
isSharded={databaseCreateNewShared}
|
||||||
|
isFreeTier={isFreeTierAccount}
|
||||||
setThroughputValue={(newThroughput: number) => (throughput = newThroughput)}
|
setThroughputValue={(newThroughput: number) => (throughput = newThroughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
|
@ -262,6 +262,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
}
|
}
|
||||||
isDatabase
|
isDatabase
|
||||||
isSharded
|
isSharded
|
||||||
|
isFreeTier={isFreeTierAccount}
|
||||||
setThroughputValue={(throughput: number) => (newKeySpaceThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (newKeySpaceThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
@ -335,6 +336,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
isSharded
|
isSharded
|
||||||
|
isFreeTier={isFreeTierAccount}
|
||||||
setThroughputValue={(throughput: number) => (tableThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (tableThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isTableAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isTableAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export type Features = {
|
export type Features = {
|
||||||
|
// set only via feature flags
|
||||||
readonly canExceedMaximumValue: boolean;
|
readonly canExceedMaximumValue: boolean;
|
||||||
readonly cosmosdb: boolean;
|
readonly cosmosdb: boolean;
|
||||||
readonly enableChangeFeedPolicy: boolean;
|
readonly enableChangeFeedPolicy: boolean;
|
||||||
@ -8,12 +9,6 @@ export type Features = {
|
|||||||
readonly enableReactPane: boolean;
|
readonly enableReactPane: boolean;
|
||||||
readonly enableRightPanelV2: boolean;
|
readonly enableRightPanelV2: boolean;
|
||||||
readonly enableSchema: boolean;
|
readonly enableSchema: boolean;
|
||||||
autoscaleDefault: boolean;
|
|
||||||
partitionKeyDefault: boolean;
|
|
||||||
partitionKeyDefault2: boolean;
|
|
||||||
phoenixNotebooks: boolean;
|
|
||||||
phoenixFeatures: boolean;
|
|
||||||
notebooksDownBanner: boolean;
|
|
||||||
readonly enableSDKoperations: boolean;
|
readonly enableSDKoperations: boolean;
|
||||||
readonly enableSpark: boolean;
|
readonly enableSpark: boolean;
|
||||||
readonly enableTtl: boolean;
|
readonly enableTtl: boolean;
|
||||||
@ -34,11 +29,22 @@ export type Features = {
|
|||||||
readonly mongoProxyEndpoint?: string;
|
readonly mongoProxyEndpoint?: string;
|
||||||
readonly mongoProxyAPIs?: string;
|
readonly mongoProxyAPIs?: string;
|
||||||
readonly enableThroughputCap: boolean;
|
readonly enableThroughputCap: boolean;
|
||||||
|
|
||||||
|
// can be set via both flight and feature flag
|
||||||
|
autoscaleDefault: boolean;
|
||||||
|
partitionKeyDefault: boolean;
|
||||||
|
partitionKeyDefault2: boolean;
|
||||||
|
phoenixNotebooks: boolean;
|
||||||
|
phoenixFeatures: boolean;
|
||||||
|
notebooksDownBanner: boolean;
|
||||||
|
freetierAutoscaleThroughput: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
|
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
|
||||||
const downcased = new URLSearchParams();
|
const downcased = new URLSearchParams();
|
||||||
const set = (value: string, key: string) => downcased.set(key.toLowerCase(), value);
|
const set = (value: string, key: string) => {
|
||||||
|
downcased.set(key.toLowerCase(), value);
|
||||||
|
};
|
||||||
const get = (key: string, defaultValue?: string) =>
|
const get = (key: string, defaultValue?: string) =>
|
||||||
downcased.get("feature." + key) ?? downcased.get(key) ?? defaultValue;
|
downcased.get("feature." + key) ?? downcased.get(key) ?? defaultValue;
|
||||||
|
|
||||||
@ -86,6 +92,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
phoenixFeatures: "true" === get("phoenixfeatures"),
|
phoenixFeatures: "true" === get("phoenixfeatures"),
|
||||||
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
||||||
enableThroughputCap: "true" === get("enablethroughputcap"),
|
enableThroughputCap: "true" === get("enablethroughputcap"),
|
||||||
|
freetierAutoscaleThroughput: "true" === get("freetierautoscalethroughput"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
export const minAutoPilotThroughput = 4000;
|
import { userContext } from "UserContext";
|
||||||
|
|
||||||
|
export const autoPilotThroughput1K = 1000;
|
||||||
export const autoPilotIncrementStep = 1000;
|
export const autoPilotIncrementStep = 1000;
|
||||||
|
export const autoPilotThroughput4K = 4000;
|
||||||
|
|
||||||
export function isValidAutoPilotThroughput(maxThroughput: number): boolean {
|
export function isValidAutoPilotThroughput(maxThroughput: number): boolean {
|
||||||
if (!maxThroughput) {
|
if (!maxThroughput) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput
|
||||||
|
? autoPilotThroughput4K
|
||||||
|
: autoPilotThroughput1K;
|
||||||
if (maxThroughput < minAutoPilotThroughput) {
|
if (maxThroughput < minAutoPilotThroughput) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -373,6 +373,9 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||||||
if (inputs.flights.indexOf(Flights.NotebooksDownBanner) !== -1) {
|
if (inputs.flights.indexOf(Flights.NotebooksDownBanner) !== -1) {
|
||||||
userContext.features.notebooksDownBanner = true;
|
userContext.features.notebooksDownBanner = true;
|
||||||
}
|
}
|
||||||
|
if (inputs.flights.indexOf(Flights.FreeTierAutoscaleThroughput) !== -1) {
|
||||||
|
userContext.features.freetierAutoscaleThroughput = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user