Skip to content

Commit

Permalink
AllowRequestContinueForThroughputControlInitError (#27702)
Browse files Browse the repository at this point in the history
* allow request to continue on init error

Co-authored-by: annie-mac <[email protected]>
Co-authored-by: Fabian Meiswinkel <[email protected]>
Co-authored-by: annie-mac <[email protected]>
  • Loading branch information
4 people authored Apr 15, 2022
1 parent df5391e commit 2dab32d
Show file tree
Hide file tree
Showing 21 changed files with 561 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ private object ThroughputControlHelper {
val throughputControlConfig = cosmosThroughputControlConfig.get

val groupConfigBuilder = new ThroughputControlGroupConfigBuilder()
.setGroupName(throughputControlConfig.groupName)
.setDefault(true)
.groupName(throughputControlConfig.groupName)
.defaultControlGroup(true)

if (throughputControlConfig.targetThroughput.isDefined) {
groupConfigBuilder.setTargetThroughput(throughputControlConfig.targetThroughput.get)
groupConfigBuilder.targetThroughput(throughputControlConfig.targetThroughput.get)
}
if (throughputControlConfig.targetThroughputThreshold.isDefined) {
groupConfigBuilder.setTargetThroughputThreshold(throughputControlConfig.targetThroughputThreshold.get)
groupConfigBuilder.targetThroughputThreshold(throughputControlConfig.targetThroughputThreshold.get)
}

val globalThroughputControlConfigBuilder = client.createGlobalThroughputControlConfigBuilder(
Expand Down
1 change: 1 addition & 0 deletions sdk/cosmos/azure-cosmos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### 4.29.0-beta.1 (Unreleased)

#### Features Added
* Added Beta API `continueOnInitError` in `ThroughputControlGroupConfigBuilder` - See [PR 27702](https://github.com/Azure/azure-sdk-for-java/pull/27702)

#### Breaking Changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@ public final class ThroughputControlGroupConfig {
private final Integer targetThroughput;
private final Double targetThroughputThreshold;
private final boolean isDefault;
private final boolean continueOnInitError;

ThroughputControlGroupConfig(String groupName, Integer targetThroughput, Double targetThroughputThreshold, boolean isDefault) {
ThroughputControlGroupConfig(
String groupName,
Integer targetThroughput,
Double targetThroughputThreshold,
boolean isDefault,
boolean continueOnInitError) {
this.groupName= groupName;
this.targetThroughput = targetThroughput;
this.targetThroughputThreshold = targetThroughputThreshold;
this.isDefault = isDefault;
this.continueOnInitError = continueOnInitError;
}

/**
Expand Down Expand Up @@ -70,4 +77,17 @@ public Double getTargetThroughputThreshold() {
public boolean isDefault() {
return this.isDefault;
}

/**
* Get whether request is allowed to continue on original request flow if throughput control controller failed on initialization.
*
* By default, it is false.
* If it is true, requests will continue on original request flow if throughput control controller failed on initialization.
*
* @return {@code true} request will continue on original request flow if throughput control controller failed on initialization. {@code false} otherwise.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public boolean isContinueOnInitError() {
return continueOnInitError;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@
*/
@Beta(value = Beta.SinceVersion.V4_13_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public class ThroughputControlGroupConfigBuilder {
private static final boolean DEFAULT_CONTINUE_ON_INIT_ERROR = false;
private String groupName;
private Integer targetThroughput;
private Double targetThroughputThreshold;
private boolean isDefault;
private boolean continueOnInitError = DEFAULT_CONTINUE_ON_INIT_ERROR;

/**
* Set the throughput control group name.
*
* @param groupName The throughput control group name.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Deprecated
@Beta(value = Beta.SinceVersion.V4_13_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder setGroupName(String groupName) {
checkArgument(StringUtils.isNotEmpty(groupName), "Group name cannot be null nor empty");
Expand All @@ -32,6 +35,20 @@ public ThroughputControlGroupConfigBuilder setGroupName(String groupName) {
return this;
}

/**
* Set the throughput control group name.
*
* @param groupName The throughput control group name.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder groupName(String groupName) {
checkArgument(StringUtils.isNotEmpty(groupName), "Group name cannot be null nor empty");

this.groupName = groupName;
return this;
}

/**
* Set the throughput control group target throughput.
*
Expand All @@ -40,6 +57,7 @@ public ThroughputControlGroupConfigBuilder setGroupName(String groupName) {
* @param targetThroughput The target throughput for the control group.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Deprecated
@Beta(value = Beta.SinceVersion.V4_13_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder setTargetThroughput(int targetThroughput) {
checkArgument(targetThroughput > 0, "Target throughput should be greater than 0");
Expand All @@ -48,6 +66,22 @@ public ThroughputControlGroupConfigBuilder setTargetThroughput(int targetThrough
return this;
}

/**
* Set the throughput control group target throughput.
*
* The target throughput value should be greater than 0.
*
* @param targetThroughput The target throughput for the control group.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder targetThroughput(int targetThroughput) {
checkArgument(targetThroughput > 0, "Target throughput should be greater than 0");

this.targetThroughput = targetThroughput;
return this;
}

/**
* Set the throughput control group target throughput threshold.
*
Expand All @@ -56,6 +90,7 @@ public ThroughputControlGroupConfigBuilder setTargetThroughput(int targetThrough
* @param targetThroughputThreshold The target throughput threshold for the control group.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Deprecated
@Beta(value = Beta.SinceVersion.V4_13_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder setTargetThroughputThreshold(double targetThroughputThreshold) {
checkArgument(targetThroughputThreshold > 0 && targetThroughputThreshold <= 1, "Target throughput threshold should between (0, 1]");
Expand All @@ -64,6 +99,21 @@ public ThroughputControlGroupConfigBuilder setTargetThroughputThreshold(double t
return this;
}

/**
* Set the throughput control group target throughput threshold.
*
* The target throughput threshold value should be between (0, 1].
*
* @param targetThroughputThreshold The target throughput threshold for the control group.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder targetThroughputThreshold(double targetThroughputThreshold) {
checkArgument(targetThroughputThreshold > 0 && targetThroughputThreshold <= 1, "Target throughput threshold should between (0, 1]");

this.targetThroughputThreshold = targetThroughputThreshold;
return this;
}

/**
* Set whether this throughput control group will be used by default.
Expand All @@ -72,9 +122,36 @@ public ThroughputControlGroupConfigBuilder setTargetThroughputThreshold(double t
* @param aDefault The flag to indicate whether the throughput control group will be used by default.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Deprecated
@Beta(value = Beta.SinceVersion.V4_13_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder setDefault(boolean aDefault) {
isDefault = aDefault;
this.isDefault = aDefault;
return this;
}

/**
* Set whether this throughput control group will be used by default.
* If set to true, requests without explicit override of the throughput control group will be routed to this group.
*
* @param aDefault The flag to indicate whether the throughput control group will be used by default.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder defaultControlGroup(boolean aDefault) {
this.isDefault = aDefault;
return this;
}

/**
* Set whether allow request to continue on original request flow if throughput control controller failed on initialization.
* If set to true, requests will be able to fall back to original request flow if throughput control controller failed on initialization.
*
* @param continueOnInitError The flag to indicate whether request is allowed to fall back to original request flow.
* @return The {@link ThroughputControlGroupConfigBuilder}.
*/
@Beta(value = Beta.SinceVersion.V4_28_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING)
public ThroughputControlGroupConfigBuilder continueOnInitError(boolean continueOnInitError) {
this.continueOnInitError = continueOnInitError;
return this;
}

Expand All @@ -92,6 +169,11 @@ public ThroughputControlGroupConfig build() {
throw new IllegalArgumentException("Neither targetThroughput nor targetThroughputThreshold is defined.");
}

return new ThroughputControlGroupConfig(groupName, this.targetThroughput, this.targetThroughputThreshold, isDefault);
return new ThroughputControlGroupConfig(
this.groupName,
this.targetThroughput,
this.targetThroughputThreshold,
this.isDefault,
this.continueOnInitError);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.cosmos.implementation.throughputControl;

import com.azure.cosmos.implementation.RxDocumentServiceRequest;
import com.azure.cosmos.implementation.apachecommons.lang.StringUtils;
import com.azure.cosmos.implementation.throughputControl.config.ThroughputControlGroupInternal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull;

public class ContainerThroughputControlGroupProperties {
private static Logger logger = LoggerFactory.getLogger(ContainerThroughputControlGroupProperties.class);

private final AtomicReference<ThroughputControlGroupInternal> defaultGroup;
private final Set<ThroughputControlGroupInternal> throughputControlGroupSet;
private final Set<String> supressInitErrorGroupSet;

public ContainerThroughputControlGroupProperties() {
this.defaultGroup = new AtomicReference<>();
this.throughputControlGroupSet = ConcurrentHashMap.newKeySet();
this.supressInitErrorGroupSet = ConcurrentHashMap.newKeySet();
}

/***
* Enable a throughput control group.
*
* @param group a {@link ThroughputControlGroupInternal}.
*
* @return the total size of distinct throughput control groups enabled on the container.
*/
public int enableThroughputControlGroup(ThroughputControlGroupInternal group) {
checkNotNull(group, "Throughput control group should not be null");

if (group.isDefault()) {
if (!this.defaultGroup.compareAndSet(null, group)) {
if (!this.defaultGroup.get().equals(group)) {
throw new IllegalArgumentException("A default group already exists");
}
}
}

if (group.isContinueOnInitError()) {
this.supressInitErrorGroupSet.add(group.getGroupName());
}

// Only throw when two different groups are using the same id (databaseId + containerId + groupName)
if (this.throughputControlGroupSet.stream()
.anyMatch(existingGroup -> Objects.equals(existingGroup.getId(), group.getId()) && !existingGroup.equals(group))) {
throw new IllegalArgumentException("Throughput control group with id " + group.getId() + " already exists");
}

this.throughputControlGroupSet.add(group);

return this.throughputControlGroupSet.size();
}

public Set<ThroughputControlGroupInternal> getThroughputControlGroupSet() {
return this.throughputControlGroupSet;
}

public boolean allowRequestToContinueOnInitError(RxDocumentServiceRequest request) {
checkNotNull(request, "Request should not be null");

String requestGroupName = request.getThroughputControlGroupName();
if (StringUtils.isEmpty(requestGroupName)) {
requestGroupName = this.defaultGroup.get().getGroupName();
}

return this.supressInitErrorGroupSet.contains(requestGroupName);
}
}
Loading

0 comments on commit 2dab32d

Please sign in to comment.