mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-06-30 02:28:44 +01:00
Initial version of Hot Partition Key Rate Limiting Policy
This commit is contained in:
Vendored
+5
@@ -17,12 +17,17 @@
|
|||||||
"test/out/**": true,
|
"test/out/**": true,
|
||||||
"workers/libs/**": true
|
"workers/libs/**": true
|
||||||
},
|
},
|
||||||
|
"js/ts.tsdk.path": "node_modules/typescript/lib",
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.organizeImports": "explicit"
|
"source.organizeImports": "explicit"
|
||||||
},
|
},
|
||||||
|
"js/ts.preferences.importModuleSpecifier": "non-relative",
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export class CapabilityNames {
|
|||||||
public static readonly EnableDynamicDataMasking: string = "EnableDynamicDataMasking";
|
public static readonly EnableDynamicDataMasking: string = "EnableDynamicDataMasking";
|
||||||
public static readonly EnableNoSQLFullTextSearchPreviewFeatures: string = "EnableNoSQLFullTextSearchPreviewFeatures";
|
public static readonly EnableNoSQLFullTextSearchPreviewFeatures: string = "EnableNoSQLFullTextSearchPreviewFeatures";
|
||||||
public static readonly EnableOnlineCopyFeature: string = "EnableOnlineContainerCopy";
|
public static readonly EnableOnlineCopyFeature: string = "EnableOnlineContainerCopy";
|
||||||
|
public static readonly EnableHotPartitionKeyThrottling: string = "EnableHotPartitionKeyThrottling";
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CapacityMode {
|
export enum CapacityMode {
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
: resource.softAllowedMaximumThroughput;
|
: resource.softAllowedMaximumThroughput;
|
||||||
|
|
||||||
const throughputBuckets = resource?.throughputBuckets;
|
const throughputBuckets = resource?.throughputBuckets;
|
||||||
|
const hotPartitionKeyRateLimitingPolicy = resource?.hotPartitionKeyRateLimitingPolicy;
|
||||||
|
|
||||||
if (autoscaleSettings) {
|
if (autoscaleSettings) {
|
||||||
return {
|
return {
|
||||||
@@ -123,6 +124,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
instantMaximumThroughput,
|
instantMaximumThroughput,
|
||||||
softAllowedMaximumThroughput,
|
softAllowedMaximumThroughput,
|
||||||
throughputBuckets,
|
throughputBuckets,
|
||||||
|
hotPartitionKeyRateLimitingPolicy,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +137,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
instantMaximumThroughput,
|
instantMaximumThroughput,
|
||||||
softAllowedMaximumThroughput,
|
softAllowedMaximumThroughput,
|
||||||
throughputBuckets,
|
throughputBuckets,
|
||||||
|
hotPartitionKeyRateLimitingPolicy,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -367,6 +367,10 @@ const createUpdateOfferBody = (params: UpdateOfferParams): ThroughputSettingsUpd
|
|||||||
body.properties.resource.throughputBuckets = throughputBuckets;
|
body.properties.resource.throughputBuckets = throughputBuckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.hotPartitionKeyRateLimitingPolicy !== undefined) {
|
||||||
|
body.properties.resource.hotPartitionKeyRateLimitingPolicy = params.hotPartitionKeyRateLimitingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -409,6 +413,10 @@ const updateOfferWithSDK = async (params: UpdateOfferParams): Promise<Offer> =>
|
|||||||
newOffer.content.offerAutopilotSettings = { maxThroughput: 0 };
|
newOffer.content.offerAutopilotSettings = { maxThroughput: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.hotPartitionKeyRateLimitingPolicy !== undefined) {
|
||||||
|
newOffer.content.hotPartitionKeyRateLimitingPolicy = params.hotPartitionKeyRateLimitingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
const sdkResponse = await client()
|
const sdkResponse = await client()
|
||||||
.offer(params.currentOffer.id)
|
.offer(params.currentOffer.id)
|
||||||
// TODO Remove casting when SDK types are fixed (https://github.com/Azure/azure-sdk-for-js/issues/10660)
|
// TODO Remove casting when SDK types are fixed (https://github.com/Azure/azure-sdk-for-js/issues/10660)
|
||||||
|
|||||||
@@ -343,6 +343,11 @@ export interface Offer {
|
|||||||
instantMaximumThroughput?: number;
|
instantMaximumThroughput?: number;
|
||||||
softAllowedMaximumThroughput?: number;
|
softAllowedMaximumThroughput?: number;
|
||||||
throughputBuckets?: ThroughputBucket[];
|
throughputBuckets?: ThroughputBucket[];
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: HotPartitionKeyRateLimitingPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HotPartitionKeyRateLimitingPolicy {
|
||||||
|
maximumPerPartitionKeyThroughputUtilizationPercent: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ThroughputBucket {
|
export interface ThroughputBucket {
|
||||||
@@ -359,6 +364,7 @@ export interface SDKOfferDefinition extends Resource {
|
|||||||
offerIsRUPerMinuteThroughputEnabled?: boolean;
|
offerIsRUPerMinuteThroughputEnabled?: boolean;
|
||||||
collectionThroughputInfo?: OfferThroughputInfo;
|
collectionThroughputInfo?: OfferThroughputInfo;
|
||||||
offerAutopilotSettings?: AutoPilotOfferSettings;
|
offerAutopilotSettings?: AutoPilotOfferSettings;
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: HotPartitionKeyRateLimitingPolicy;
|
||||||
};
|
};
|
||||||
resource?: string;
|
resource?: string;
|
||||||
offerResourceId?: string;
|
offerResourceId?: string;
|
||||||
@@ -492,6 +498,7 @@ export interface UpdateOfferParams {
|
|||||||
migrateToAutoPilot?: boolean;
|
migrateToAutoPilot?: boolean;
|
||||||
migrateToManual?: boolean;
|
migrateToManual?: boolean;
|
||||||
throughputBuckets?: ThroughputBucket[];
|
throughputBuckets?: ThroughputBucket[];
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: HotPartitionKeyRateLimitingPolicy | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Notification {
|
export interface Notification {
|
||||||
|
|||||||
@@ -17,25 +17,25 @@ import { useIndexingPolicyStore } from "Explorer/Tabs/QueryTab/ResultsView";
|
|||||||
import { useDatabases } from "Explorer/useDatabases";
|
import { useDatabases } from "Explorer/useDatabases";
|
||||||
import { Keys, t } from "Localization";
|
import { Keys, t } from "Localization";
|
||||||
import { isFabricNative } from "Platform/Fabric/FabricUtil";
|
import { isFabricNative } from "Platform/Fabric/FabricUtil";
|
||||||
import { isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
|
||||||
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { isHotPartitionKeyThrottlingEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||||
|
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
|
||||||
import DiscardIcon from "../../../../images/discard.svg";
|
import DiscardIcon from "../../../../images/discard.svg";
|
||||||
import SaveIcon from "../../../../images/save-cosmos.svg";
|
import SaveIcon from "../../../../images/save-cosmos.svg";
|
||||||
import { AuthType } from "../../../AuthType";
|
import { AuthType } from "../../../AuthType";
|
||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
|
||||||
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
||||||
import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readMongoDBCollection";
|
import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readMongoDBCollection";
|
||||||
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
|
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
|
||||||
import { MongoDBCollectionResource, MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
|
import { MongoDBCollectionResource, MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
|
||||||
|
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
import {
|
import {
|
||||||
PartitionKeyComponent,
|
PartitionKeyComponent,
|
||||||
@@ -65,16 +65,16 @@ import {
|
|||||||
AddMongoIndexProps,
|
AddMongoIndexProps,
|
||||||
ChangeFeedPolicyState,
|
ChangeFeedPolicyState,
|
||||||
GeospatialConfigType,
|
GeospatialConfigType,
|
||||||
MongoIndexTypes,
|
|
||||||
SettingsV2TabTypes,
|
|
||||||
TtlType,
|
|
||||||
getMongoNotification,
|
getMongoNotification,
|
||||||
getTabTitle,
|
getTabTitle,
|
||||||
hasDatabaseSharedThroughput,
|
hasDatabaseSharedThroughput,
|
||||||
isDataMaskingEnabled,
|
isDataMaskingEnabled,
|
||||||
isDirty,
|
isDirty,
|
||||||
|
MongoIndexTypes,
|
||||||
parseConflictResolutionMode,
|
parseConflictResolutionMode,
|
||||||
parseConflictResolutionProcedure,
|
parseConflictResolutionProcedure,
|
||||||
|
SettingsV2TabTypes,
|
||||||
|
TtlType,
|
||||||
} from "./SettingsUtils";
|
} from "./SettingsUtils";
|
||||||
interface SettingsV2TabInfo {
|
interface SettingsV2TabInfo {
|
||||||
tab: SettingsV2TabTypes;
|
tab: SettingsV2TabTypes;
|
||||||
@@ -103,6 +103,8 @@ export interface SettingsComponentState {
|
|||||||
throughputBuckets: DataModels.ThroughputBucket[];
|
throughputBuckets: DataModels.ThroughputBucket[];
|
||||||
throughputBucketsBaseline: DataModels.ThroughputBucket[];
|
throughputBucketsBaseline: DataModels.ThroughputBucket[];
|
||||||
throughputError: string;
|
throughputError: string;
|
||||||
|
hotPartitionKeyRateLimitingPolicy: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
|
||||||
timeToLive: TtlType;
|
timeToLive: TtlType;
|
||||||
timeToLiveBaseline: TtlType;
|
timeToLiveBaseline: TtlType;
|
||||||
@@ -225,6 +227,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
throughputBuckets: undefined,
|
throughputBuckets: undefined,
|
||||||
throughputBucketsBaseline: undefined,
|
throughputBucketsBaseline: undefined,
|
||||||
throughputError: undefined,
|
throughputError: undefined,
|
||||||
|
hotPartitionKeyRateLimitingPolicy: null,
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline: null,
|
||||||
|
|
||||||
timeToLive: undefined,
|
timeToLive: undefined,
|
||||||
timeToLiveBaseline: undefined,
|
timeToLiveBaseline: undefined,
|
||||||
@@ -495,6 +499,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
throughput: this.state.throughputBaseline,
|
throughput: this.state.throughputBaseline,
|
||||||
throughputBuckets: this.state.throughputBucketsBaseline,
|
throughputBuckets: this.state.throughputBucketsBaseline,
|
||||||
throughputBucketsBaseline: this.state.throughputBucketsBaseline,
|
throughputBucketsBaseline: this.state.throughputBucketsBaseline,
|
||||||
|
hotPartitionKeyRateLimitingPolicy: this.state.hotPartitionKeyRateLimitingPolicyBaseline,
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline: this.state.hotPartitionKeyRateLimitingPolicyBaseline,
|
||||||
timeToLive: this.state.timeToLiveBaseline,
|
timeToLive: this.state.timeToLiveBaseline,
|
||||||
timeToLiveSeconds: this.state.timeToLiveSecondsBaseline,
|
timeToLiveSeconds: this.state.timeToLiveSecondsBaseline,
|
||||||
displayedTtlSeconds: this.state.displayedTtlSecondsBaseline,
|
displayedTtlSeconds: this.state.displayedTtlSecondsBaseline,
|
||||||
@@ -877,12 +883,15 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
] as DataModels.ComputedProperties;
|
] as DataModels.ComputedProperties;
|
||||||
}
|
}
|
||||||
const throughputBuckets = this.offer?.throughputBuckets;
|
const throughputBuckets = this.offer?.throughputBuckets;
|
||||||
|
const hotPartitionKeyRateLimitingPolicy = this.offer?.hotPartitionKeyRateLimitingPolicy ?? null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
throughput: offerThroughput,
|
throughput: offerThroughput,
|
||||||
throughputBaseline: offerThroughput,
|
throughputBaseline: offerThroughput,
|
||||||
throughputBuckets,
|
throughputBuckets,
|
||||||
throughputBucketsBaseline: throughputBuckets,
|
throughputBucketsBaseline: throughputBuckets,
|
||||||
|
hotPartitionKeyRateLimitingPolicy,
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline: hotPartitionKeyRateLimitingPolicy,
|
||||||
changeFeedPolicy: changeFeedPolicy,
|
changeFeedPolicy: changeFeedPolicy,
|
||||||
changeFeedPolicyBaseline: changeFeedPolicy,
|
changeFeedPolicyBaseline: changeFeedPolicy,
|
||||||
timeToLive: timeToLive,
|
timeToLive: timeToLive,
|
||||||
@@ -984,6 +993,12 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
this.setState({ throughputBuckets });
|
this.setState({ throughputBuckets });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onHotPartitionKeyRateLimitingPolicyChange = (
|
||||||
|
hotPartitionKeyRateLimitingPolicy: DataModels.HotPartitionKeyRateLimitingPolicy,
|
||||||
|
): void => {
|
||||||
|
this.setState({ hotPartitionKeyRateLimitingPolicy });
|
||||||
|
};
|
||||||
|
|
||||||
private onAutoPilotSelected = (isAutoPilotSelected: boolean): void =>
|
private onAutoPilotSelected = (isAutoPilotSelected: boolean): void =>
|
||||||
this.setState({ isAutoPilotSelected: isAutoPilotSelected });
|
this.setState({ isAutoPilotSelected: isAutoPilotSelected });
|
||||||
|
|
||||||
@@ -999,6 +1014,9 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
currentOffer: this.database.offer(),
|
currentOffer: this.database.offer(),
|
||||||
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
|
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
|
||||||
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
|
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
|
||||||
|
hotPartitionKeyRateLimitingPolicy: isHotPartitionKeyThrottlingEnabled()
|
||||||
|
? this.state.hotPartitionKeyRateLimitingPolicy ?? null
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
if (this.hasProvisioningTypeChanged()) {
|
if (this.hasProvisioningTypeChanged()) {
|
||||||
if (this.state.isAutoPilotSelected) {
|
if (this.state.isAutoPilotSelected) {
|
||||||
@@ -1232,6 +1250,9 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
|
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
|
||||||
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
|
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
|
||||||
throughputBuckets: this.throughputBucketsEnabled ? this.state.throughputBuckets : undefined,
|
throughputBuckets: this.throughputBucketsEnabled ? this.state.throughputBuckets : undefined,
|
||||||
|
hotPartitionKeyRateLimitingPolicy: isHotPartitionKeyThrottlingEnabled()
|
||||||
|
? this.state.hotPartitionKeyRateLimitingPolicy ?? null
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
if (this.hasProvisioningTypeChanged()) {
|
if (this.hasProvisioningTypeChanged()) {
|
||||||
if (this.state.isAutoPilotSelected) {
|
if (this.state.isAutoPilotSelected) {
|
||||||
@@ -1300,6 +1321,9 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
onScaleSaveableChange: this.onScaleSaveableChange,
|
onScaleSaveableChange: this.onScaleSaveableChange,
|
||||||
onScaleDiscardableChange: this.onScaleDiscardableChange,
|
onScaleDiscardableChange: this.onScaleDiscardableChange,
|
||||||
throughputError: this.state.throughputError,
|
throughputError: this.state.throughputError,
|
||||||
|
hotPartitionKeyRateLimitingPolicy: this.state.hotPartitionKeyRateLimitingPolicy,
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline: this.state.hotPartitionKeyRateLimitingPolicyBaseline,
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange: this.onHotPartitionKeyRateLimitingPolicyChange,
|
||||||
};
|
};
|
||||||
if (!this.isCollectionSettingsTab) {
|
if (!this.isCollectionSettingsTab) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ describe("ScaleComponent", () => {
|
|||||||
onScaleDiscardableChange: () => {
|
onScaleDiscardableChange: () => {
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange: () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it("autoScale disabled", () => {
|
it("autoScale disabled", () => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Link, MessageBar, MessageBarType, Stack, Text, TextField } from "@fluen
|
|||||||
import { Keys, t } from "Localization";
|
import { Keys, t } from "Localization";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Constants from "../../../../Common/Constants";
|
import * as Constants from "../../../../Common/Constants";
|
||||||
import { Platform, configContext } from "../../../../ConfigContext";
|
import { configContext, Platform } from "../../../../ConfigContext";
|
||||||
import * as DataModels from "../../../../Contracts/DataModels";
|
import * as DataModels from "../../../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../../Contracts/ViewModels";
|
||||||
import * as SharedConstants from "../../../../Shared/Constants";
|
import * as SharedConstants from "../../../../Shared/Constants";
|
||||||
@@ -36,6 +36,9 @@ export interface ScaleComponentProps {
|
|||||||
onScaleSaveableChange: (isScaleSaveable: boolean) => void;
|
onScaleSaveableChange: (isScaleSaveable: boolean) => void;
|
||||||
onScaleDiscardableChange: (isScaleDiscardable: boolean) => void;
|
onScaleDiscardableChange: (isScaleDiscardable: boolean) => void;
|
||||||
throughputError?: string;
|
throughputError?: string;
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline?: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange: (newPolicy: DataModels.HotPartitionKeyRateLimitingPolicy) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
||||||
@@ -148,6 +151,9 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
|||||||
instantMaximumThroughput={this.offer?.instantMaximumThroughput}
|
instantMaximumThroughput={this.offer?.instantMaximumThroughput}
|
||||||
softAllowedMaximumThroughput={this.offer?.softAllowedMaximumThroughput}
|
softAllowedMaximumThroughput={this.offer?.softAllowedMaximumThroughput}
|
||||||
isGlobalSecondaryIndex={this.props.isGlobalSecondaryIndex}
|
isGlobalSecondaryIndex={this.props.isGlobalSecondaryIndex}
|
||||||
|
hotPartitionKeyRateLimitingPolicy={this.props.hotPartitionKeyRateLimitingPolicy}
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline={this.props.hotPartitionKeyRateLimitingPolicyBaseline}
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange={this.props.onHotPartitionKeyRateLimitingPolicyChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+15
@@ -1,12 +1,24 @@
|
|||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import * as Constants from "../../../../../Common/Constants";
|
||||||
import * as DataModels from "../../../../../Contracts/DataModels";
|
import * as DataModels from "../../../../../Contracts/DataModels";
|
||||||
|
import { updateUserContext } from "../../../../../UserContext";
|
||||||
import {
|
import {
|
||||||
ThroughputInputAutoPilotV3Component,
|
ThroughputInputAutoPilotV3Component,
|
||||||
ThroughputInputAutoPilotV3Props,
|
ThroughputInputAutoPilotV3Props,
|
||||||
} from "./ThroughputInputAutoPilotV3Component";
|
} from "./ThroughputInputAutoPilotV3Component";
|
||||||
|
|
||||||
describe("ThroughputInputAutoPilotV3Component", () => {
|
describe("ThroughputInputAutoPilotV3Component", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [{ name: Constants.CapabilityNames.EnableHotPartitionKeyThrottling }],
|
||||||
|
},
|
||||||
|
} as DataModels.DatabaseAccount,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const baseProps: ThroughputInputAutoPilotV3Props = {
|
const baseProps: ThroughputInputAutoPilotV3Props = {
|
||||||
databaseAccount: {} as DataModels.DatabaseAccount,
|
databaseAccount: {} as DataModels.DatabaseAccount,
|
||||||
databaseName: "test",
|
databaseName: "test",
|
||||||
@@ -45,6 +57,9 @@ describe("ThroughputInputAutoPilotV3Component", () => {
|
|||||||
instantMaximumThroughput: 5000,
|
instantMaximumThroughput: 5000,
|
||||||
softAllowedMaximumThroughput: 1000000,
|
softAllowedMaximumThroughput: 1000000,
|
||||||
isGlobalSecondaryIndex: false,
|
isGlobalSecondaryIndex: false,
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange: () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it("throughput input visible", () => {
|
it("throughput input visible", () => {
|
||||||
|
|||||||
+59
-2
@@ -12,9 +12,11 @@ import {
|
|||||||
MessageBarType,
|
MessageBarType,
|
||||||
ProgressIndicator,
|
ProgressIndicator,
|
||||||
Separator,
|
Separator,
|
||||||
|
Slider,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextField,
|
TextField,
|
||||||
|
Toggle,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
import { Keys, t } from "Localization";
|
import { Keys, t } from "Localization";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
@@ -25,10 +27,10 @@ import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryPr
|
|||||||
import { userContext } from "../../../../../UserContext";
|
import { userContext } from "../../../../../UserContext";
|
||||||
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
||||||
import { autoPilotThroughput1K } from "../../../../../Utils/AutoPilotUtils";
|
import { autoPilotThroughput1K } from "../../../../../Utils/AutoPilotUtils";
|
||||||
|
import { isHotPartitionKeyThrottlingEnabled } from "../../../../../Utils/CapabilityUtils";
|
||||||
import { calculateEstimateNumber } from "../../../../../Utils/PricingUtils";
|
import { calculateEstimateNumber } from "../../../../../Utils/PricingUtils";
|
||||||
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
||||||
import {
|
import {
|
||||||
PriceBreakdown,
|
|
||||||
checkBoxAndInputStackProps,
|
checkBoxAndInputStackProps,
|
||||||
getChoiceGroupStyles,
|
getChoiceGroupStyles,
|
||||||
getEstimatedSpendingElement,
|
getEstimatedSpendingElement,
|
||||||
@@ -40,11 +42,12 @@ import {
|
|||||||
getUpdateThroughputBeyondSupportLimitMessage,
|
getUpdateThroughputBeyondSupportLimitMessage,
|
||||||
manualToAutoscaleDisclaimerElement,
|
manualToAutoscaleDisclaimerElement,
|
||||||
noLeftPaddingCheckBoxStyle,
|
noLeftPaddingCheckBoxStyle,
|
||||||
|
PriceBreakdown,
|
||||||
relaxedSpacingStackProps,
|
relaxedSpacingStackProps,
|
||||||
saveThroughputWarningMessage,
|
saveThroughputWarningMessage,
|
||||||
titleAndInputStackProps,
|
titleAndInputStackProps,
|
||||||
} from "../../SettingsRenderUtils";
|
} from "../../SettingsRenderUtils";
|
||||||
import { IsComponentDirtyResult, getSanitizedInputValue, isDirty } from "../../SettingsUtils";
|
import { getSanitizedInputValue, IsComponentDirtyResult, isDirty } from "../../SettingsUtils";
|
||||||
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
|
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
|
||||||
|
|
||||||
export interface ThroughputInputAutoPilotV3Props {
|
export interface ThroughputInputAutoPilotV3Props {
|
||||||
@@ -82,6 +85,9 @@ export interface ThroughputInputAutoPilotV3Props {
|
|||||||
instantMaximumThroughput: number;
|
instantMaximumThroughput: number;
|
||||||
softAllowedMaximumThroughput: number;
|
softAllowedMaximumThroughput: number;
|
||||||
isGlobalSecondaryIndex: boolean;
|
isGlobalSecondaryIndex: boolean;
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline?: DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange: (newPolicy: DataModels.HotPartitionKeyRateLimitingPolicy) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThroughputInputAutoPilotV3State {
|
interface ThroughputInputAutoPilotV3State {
|
||||||
@@ -137,6 +143,12 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
if (this.hasProvisioningTypeChanged()) {
|
if (this.hasProvisioningTypeChanged()) {
|
||||||
isSaveable = true;
|
isSaveable = true;
|
||||||
isDiscardable = true;
|
isDiscardable = true;
|
||||||
|
} else if (
|
||||||
|
isHotPartitionKeyThrottlingEnabled() &&
|
||||||
|
isDirty(this.props.hotPartitionKeyRateLimitingPolicy, this.props.hotPartitionKeyRateLimitingPolicyBaseline)
|
||||||
|
) {
|
||||||
|
isSaveable = true;
|
||||||
|
isDiscardable = true;
|
||||||
} else if (this.props.isAutoPilotSelected) {
|
} else if (this.props.isAutoPilotSelected) {
|
||||||
if (isDirty(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline)) {
|
if (isDirty(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline)) {
|
||||||
isDiscardable = true;
|
isDiscardable = true;
|
||||||
@@ -865,6 +877,50 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private renderPartitionKeyRateLimitingPolicy = (): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<Stack {...titleAndInputStackProps} style={{ maxWidth: "700px" }}>
|
||||||
|
<Stack horizontal>
|
||||||
|
<ToolTipLabelComponent
|
||||||
|
label={t(Keys.controls.settings.scale.rateLimitingPolicyTitle)}
|
||||||
|
toolTipElement={null}
|
||||||
|
/>
|
||||||
|
<Toggle
|
||||||
|
onText={t(Keys.common.on)}
|
||||||
|
offText={t(Keys.common.off)}
|
||||||
|
checked={!!this.props.hotPartitionKeyRateLimitingPolicy}
|
||||||
|
onChange={(_ev, checked) => {
|
||||||
|
if (checked) {
|
||||||
|
this.props.onHotPartitionKeyRateLimitingPolicyChange({
|
||||||
|
maximumPerPartitionKeyThroughputUtilizationPercent:
|
||||||
|
this.props.hotPartitionKeyRateLimitingPolicyBaseline
|
||||||
|
?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.props.onHotPartitionKeyRateLimitingPolicyChange(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<Slider
|
||||||
|
disabled={!this.props.hotPartitionKeyRateLimitingPolicy}
|
||||||
|
label={t(Keys.controls.settings.scale.rateLimitPolicyMaxThroughputUtilizationLabel)}
|
||||||
|
min={51}
|
||||||
|
max={100}
|
||||||
|
ariaValueText={(value: number) => `${value} percent`}
|
||||||
|
valueFormat={(value: number) => `${value}%`}
|
||||||
|
showValue
|
||||||
|
value={this.props.hotPartitionKeyRateLimitingPolicy?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75}
|
||||||
|
onChange={(value: number) =>
|
||||||
|
this.props.onHotPartitionKeyRateLimitingPolicyChange({
|
||||||
|
maximumPerPartitionKeyThroughputUtilizationPercent: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...checkBoxAndInputStackProps}>
|
<Stack {...checkBoxAndInputStackProps}>
|
||||||
@@ -872,6 +928,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
{this.renderThroughputModeChoices()}
|
{this.renderThroughputModeChoices()}
|
||||||
|
|
||||||
{this.renderThroughputComponent()}
|
{this.renderThroughputComponent()}
|
||||||
|
{isHotPartitionKeyThrottlingEnabled() && this.renderPartitionKeyRateLimitingPolicy()}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+114
@@ -797,6 +797,44 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
|
|||||||
</Stack>
|
</Stack>
|
||||||
</StackItem>
|
</StackItem>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"maxWidth": "700px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens={
|
||||||
|
{
|
||||||
|
"childrenGap": 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
horizontal={true}
|
||||||
|
>
|
||||||
|
<ToolTipLabelComponent
|
||||||
|
label="Rate limiting policy"
|
||||||
|
toolTipElement={null}
|
||||||
|
/>
|
||||||
|
<StyledToggleBase
|
||||||
|
checked={false}
|
||||||
|
offText="Off"
|
||||||
|
onChange={[Function]}
|
||||||
|
onText="On"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<StyledSliderBase
|
||||||
|
ariaValueText={[Function]}
|
||||||
|
disabled={true}
|
||||||
|
label="Max per partition key Throughput utilization"
|
||||||
|
max={100}
|
||||||
|
min={51}
|
||||||
|
onChange={[Function]}
|
||||||
|
showValue={true}
|
||||||
|
value={75}
|
||||||
|
valueFormat={[Function]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -1372,6 +1410,44 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
</Stack>
|
</Stack>
|
||||||
</StackItem>
|
</StackItem>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"maxWidth": "700px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens={
|
||||||
|
{
|
||||||
|
"childrenGap": 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
horizontal={true}
|
||||||
|
>
|
||||||
|
<ToolTipLabelComponent
|
||||||
|
label="Rate limiting policy"
|
||||||
|
toolTipElement={null}
|
||||||
|
/>
|
||||||
|
<StyledToggleBase
|
||||||
|
checked={false}
|
||||||
|
offText="Off"
|
||||||
|
onChange={[Function]}
|
||||||
|
onText="On"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<StyledSliderBase
|
||||||
|
ariaValueText={[Function]}
|
||||||
|
disabled={true}
|
||||||
|
label="Max per partition key Throughput utilization"
|
||||||
|
max={100}
|
||||||
|
min={51}
|
||||||
|
onChange={[Function]}
|
||||||
|
showValue={true}
|
||||||
|
value={75}
|
||||||
|
valueFormat={[Function]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -1930,5 +2006,43 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
|
|||||||
</Stack>
|
</Stack>
|
||||||
</StackItem>
|
</StackItem>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
<Stack
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"maxWidth": "700px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens={
|
||||||
|
{
|
||||||
|
"childrenGap": 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Stack
|
||||||
|
horizontal={true}
|
||||||
|
>
|
||||||
|
<ToolTipLabelComponent
|
||||||
|
label="Rate limiting policy"
|
||||||
|
toolTipElement={null}
|
||||||
|
/>
|
||||||
|
<StyledToggleBase
|
||||||
|
checked={false}
|
||||||
|
offText="Off"
|
||||||
|
onChange={[Function]}
|
||||||
|
onText="On"
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<StyledSliderBase
|
||||||
|
ariaValueText={[Function]}
|
||||||
|
disabled={true}
|
||||||
|
label="Max per partition key Throughput utilization"
|
||||||
|
max={100}
|
||||||
|
min={51}
|
||||||
|
onChange={[Function]}
|
||||||
|
showValue={true}
|
||||||
|
value={75}
|
||||||
|
valueFormat={[Function]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import * as Constants from "../../../Common/Constants";
|
|||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
import { isCapabilityEnabled } from "../../../Utils/CapabilityUtils";
|
|
||||||
import { MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
|
import { MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
|
||||||
|
import { isCapabilityEnabled } from "../../../Utils/CapabilityUtils";
|
||||||
|
|
||||||
const zeroValue = 0;
|
const zeroValue = 0;
|
||||||
export type isDirtyTypes =
|
export type isDirtyTypes =
|
||||||
@@ -17,7 +17,8 @@ export type isDirtyTypes =
|
|||||||
| DataModels.VectorIndex[]
|
| DataModels.VectorIndex[]
|
||||||
| DataModels.FullTextPolicy
|
| DataModels.FullTextPolicy
|
||||||
| DataModels.ThroughputBucket[]
|
| DataModels.ThroughputBucket[]
|
||||||
| DataModels.DataMaskingPolicy;
|
| DataModels.DataMaskingPolicy
|
||||||
|
| DataModels.HotPartitionKeyRateLimitingPolicy;
|
||||||
export const TtlOff = "off";
|
export const TtlOff = "off";
|
||||||
export const TtlOn = "on";
|
export const TtlOn = "on";
|
||||||
export const TtlOnNoDefault = "on-nodefault";
|
export const TtlOnNoDefault = "on-nodefault";
|
||||||
|
|||||||
@@ -179,10 +179,13 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"vectorEmbeddingPolicy": [Function],
|
"vectorEmbeddingPolicy": [Function],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hotPartitionKeyRateLimitingPolicy={null}
|
||||||
|
hotPartitionKeyRateLimitingPolicyBaseline={null}
|
||||||
isAutoPilotSelected={false}
|
isAutoPilotSelected={false}
|
||||||
isFixedContainer={false}
|
isFixedContainer={false}
|
||||||
isGlobalSecondaryIndex={true}
|
isGlobalSecondaryIndex={true}
|
||||||
onAutoPilotSelected={[Function]}
|
onAutoPilotSelected={[Function]}
|
||||||
|
onHotPartitionKeyRateLimitingPolicyChange={[Function]}
|
||||||
onMaxAutoPilotThroughputChange={[Function]}
|
onMaxAutoPilotThroughputChange={[Function]}
|
||||||
onScaleDiscardableChange={[Function]}
|
onScaleDiscardableChange={[Function]}
|
||||||
onScaleSaveableChange={[Function]}
|
onScaleSaveableChange={[Function]}
|
||||||
|
|||||||
@@ -894,7 +894,9 @@
|
|||||||
"autoScaleCustomSettings": "Your account has custom settings that prevents setting throughput at the container level. Please work with your Cosmos DB engineering team point of contact to make changes.",
|
"autoScaleCustomSettings": "Your account has custom settings that prevents setting throughput at the container level. Please work with your Cosmos DB engineering team point of contact to make changes.",
|
||||||
"keyspaceSharedThroughput": "This table shared throughput is configured at the keyspace",
|
"keyspaceSharedThroughput": "This table shared throughput is configured at the keyspace",
|
||||||
"throughputRangeLabel": "Throughput ({{min}} - {{max}} RU/s)",
|
"throughputRangeLabel": "Throughput ({{min}} - {{max}} RU/s)",
|
||||||
"unlimited": "unlimited"
|
"unlimited": "unlimited",
|
||||||
|
"rateLimitingPolicyTitle": "Rate limiting policy",
|
||||||
|
"rateLimitPolicyMaxThroughputUtilizationLabel": "Max per partition key Throughput utilization"
|
||||||
},
|
},
|
||||||
"partitionKeyEditor": {
|
"partitionKeyEditor": {
|
||||||
"changePartitionKey": "Change {{partitionKeyName}}",
|
"changePartitionKey": "Change {{partitionKeyName}}",
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import * as Constants from "../Common/Constants";
|
||||||
|
import { DatabaseAccount } from "../Contracts/DataModels";
|
||||||
|
import { updateUserContext } from "../UserContext";
|
||||||
|
import { isHotPartitionKeyThrottlingEnabled } from "./CapabilityUtils";
|
||||||
|
|
||||||
|
describe("CapabilityUtils", () => {
|
||||||
|
describe("isHotPartitionKeyThrottlingEnabled", () => {
|
||||||
|
it("returns true for a SQL account with the EnableHotPartitionKeyThrottling capability", () => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [{ name: Constants.CapabilityNames.EnableHotPartitionKeyThrottling }],
|
||||||
|
},
|
||||||
|
} as DatabaseAccount,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(isHotPartitionKeyThrottlingEnabled()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for a SQL account without the capability", () => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [{ name: Constants.CapabilityNames.EnableAutoScale }],
|
||||||
|
},
|
||||||
|
} as DatabaseAccount,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(isHotPartitionKeyThrottlingEnabled()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for a non-SQL account even with the capability", () => {
|
||||||
|
updateUserContext({
|
||||||
|
databaseAccount: {
|
||||||
|
properties: {
|
||||||
|
capabilities: [
|
||||||
|
{ name: Constants.CapabilityNames.EnableCassandra },
|
||||||
|
{ name: Constants.CapabilityNames.EnableHotPartitionKeyThrottling },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} as DatabaseAccount,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(isHotPartitionKeyThrottlingEnabled()).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -34,3 +34,10 @@ export const isFullTextSearchPreviewFeaturesEnabled = (targetAccountOverride?: A
|
|||||||
isCapabilityEnabled(Constants.CapabilityNames.EnableNoSQLFullTextSearchPreviewFeatures, targetAccountOverride)
|
isCapabilityEnabled(Constants.CapabilityNames.EnableNoSQLFullTextSearchPreviewFeatures, targetAccountOverride)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isHotPartitionKeyThrottlingEnabled = (targetAccountOverride?: AccountOverride): boolean => {
|
||||||
|
return (
|
||||||
|
userContext.apiType === "SQL" &&
|
||||||
|
isCapabilityEnabled(Constants.CapabilityNames.EnableHotPartitionKeyThrottling, targetAccountOverride)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1096,6 +1096,11 @@ export interface CassandraViewCreateUpdateProperties {
|
|||||||
options?: CreateUpdateOptions;
|
options?: CreateUpdateOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HotPartitionKeyRateLimitingPolicy {
|
||||||
|
/* Maximum throughput utilization for partition keys (in percent) */
|
||||||
|
maximumPerPartitionKeyThroughputUtilizationPercent: number;
|
||||||
|
}
|
||||||
|
|
||||||
/* Cosmos DB resource throughput object. Either throughput is required or autoscaleSettings is required, but not both. */
|
/* Cosmos DB resource throughput object. Either throughput is required or autoscaleSettings is required, but not both. */
|
||||||
export interface ThroughputSettingsResource {
|
export interface ThroughputSettingsResource {
|
||||||
/* Value of the Cosmos DB resource throughput. Either throughput is required or autoscaleSettings is required, but not both. */
|
/* Value of the Cosmos DB resource throughput. Either throughput is required or autoscaleSettings is required, but not both. */
|
||||||
@@ -1113,6 +1118,8 @@ export interface ThroughputSettingsResource {
|
|||||||
readonly softAllowedMaximumThroughput?: string;
|
readonly softAllowedMaximumThroughput?: string;
|
||||||
/* Array of throughput bucket limits to be applied to the Cosmos DB container */
|
/* Array of throughput bucket limits to be applied to the Cosmos DB container */
|
||||||
throughputBuckets?: ThroughputBucketResource[];
|
throughputBuckets?: ThroughputBucketResource[];
|
||||||
|
/* Object describing the Rate Limiting policy for Hot Partition Keys */
|
||||||
|
hotPartitionKeyRateLimitingPolicy?: HotPartitionKeyRateLimitingPolicy | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cosmos DB provisioned throughput settings object */
|
/* Cosmos DB provisioned throughput settings object */
|
||||||
|
|||||||
@@ -98,6 +98,7 @@
|
|||||||
"./src/Utils/Base64Utils.ts",
|
"./src/Utils/Base64Utils.ts",
|
||||||
"./src/Utils/BlobUtils.ts",
|
"./src/Utils/BlobUtils.ts",
|
||||||
"./src/Utils/CapabilityUtils.ts",
|
"./src/Utils/CapabilityUtils.ts",
|
||||||
|
"./src/Utils/CapabilityUtils.test.ts",
|
||||||
"./src/Utils/CloudUtils.ts",
|
"./src/Utils/CloudUtils.ts",
|
||||||
"./src/Utils/EndpointUtils.ts",
|
"./src/Utils/EndpointUtils.ts",
|
||||||
"./src/Utils/GitHubUtils.test.ts",
|
"./src/Utils/GitHubUtils.test.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user