Skip to content

Commit af04043

Browse files
Introduce durability of circuit breaking exception
With this commit we differentiate between permanent circuit breaking exceptions (which require intervention from an operator and should not be automatically retried) and transient ones (which may heal themselves eventually and should be retried). Furthermore, the parent circuit breaker will categorize a circuit breaking exception as either transient or permanent based on the categorization of memory usage of its child circuit breakers. Closes elastic#31986
1 parent 56c99f9 commit af04043

File tree

13 files changed

+191
-58
lines changed

13 files changed

+191
-58
lines changed

modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.action.search.ShardSearchFailure;
2525
import org.elasticsearch.cluster.block.ClusterBlockException;
2626
import org.elasticsearch.common.ParsingException;
27+
import org.elasticsearch.common.breaker.CircuitBreaker;
2728
import org.elasticsearch.common.breaker.CircuitBreakingException;
2829
import org.elasticsearch.common.bytes.BytesReference;
2930
import org.elasticsearch.common.io.stream.BytesStreamOutput;
@@ -63,7 +64,7 @@ public class RankEvalResponseTests extends ESTestCase {
6364

6465
private static final Exception[] RANDOM_EXCEPTIONS = new Exception[] {
6566
new ClusterBlockException(singleton(DiscoverySettings.NO_MASTER_BLOCK_WRITES)),
66-
new CircuitBreakingException("Data too large", 123, 456),
67+
new CircuitBreakingException("Data too large", 123, 456, CircuitBreaker.Durability.PERMANENT),
6768
new SearchParseException(new TestSearchContext(null), "Parse failure", new XContentLocation(12, 98)),
6869
new IllegalArgumentException("Closed resource", new RuntimeException("Resource")),
6970
new SearchPhaseExecutionException("search", "all shards failed",

server/src/main/java/org/elasticsearch/common/breaker/ChildMemoryCircuitBreaker.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
public class ChildMemoryCircuitBreaker implements CircuitBreaker {
3333

3434
private final long memoryBytesLimit;
35-
private final BreakerSettings settings;
3635
private final double overheadConstant;
36+
private final Durability durability;
3737
private final AtomicLong used;
3838
private final AtomicLong trippedCount;
3939
private final Logger logger;
@@ -66,9 +66,9 @@ public ChildMemoryCircuitBreaker(BreakerSettings settings, Logger logger,
6666
public ChildMemoryCircuitBreaker(BreakerSettings settings, ChildMemoryCircuitBreaker oldBreaker,
6767
Logger logger, HierarchyCircuitBreakerService parent, String name) {
6868
this.name = name;
69-
this.settings = settings;
7069
this.memoryBytesLimit = settings.getLimit();
7170
this.overheadConstant = settings.getOverhead();
71+
this.durability = settings.getDurability();
7272
if (oldBreaker == null) {
7373
this.used = new AtomicLong(0);
7474
this.trippedCount = new AtomicLong(0);
@@ -78,7 +78,7 @@ public ChildMemoryCircuitBreaker(BreakerSettings settings, ChildMemoryCircuitBre
7878
}
7979
this.logger = logger;
8080
if (logger.isTraceEnabled()) {
81-
logger.trace("creating ChildCircuitBreaker with settings {}", this.settings);
81+
logger.trace("creating ChildCircuitBreaker with settings {}", settings);
8282
}
8383
this.parent = parent;
8484
}
@@ -95,7 +95,7 @@ public void circuitBreak(String fieldName, long bytesNeeded) {
9595
", which is larger than the limit of [" +
9696
memoryBytesLimit + "/" + new ByteSizeValue(memoryBytesLimit) + "]";
9797
logger.debug("{}", message);
98-
throw new CircuitBreakingException(message, bytesNeeded, memoryBytesLimit);
98+
throw new CircuitBreakingException(message, bytesNeeded, memoryBytesLimit, durability);
9999
}
100100

101101
/**
@@ -234,4 +234,12 @@ public long getTrippedCount() {
234234
public String getName() {
235235
return this.name;
236236
}
237+
238+
/**
239+
* @return whether a tripped circuit breaker will reset itself (transient) or requires manual intervention (permanent).
240+
*/
241+
@Override
242+
public Durability getDurability() {
243+
return this.durability;
244+
}
237245
}

server/src/main/java/org/elasticsearch/common/breaker/CircuitBreaker.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ public static Type parseValue(String value) {
8383
}
8484
}
8585

86+
enum Durability {
87+
// The condition that tripped the circuit breaker fixes itself eventually.
88+
TRANSIENT,
89+
// The condition that tripped the circuit breaker requires manual intervention.
90+
PERMANENT
91+
}
92+
8693
/**
8794
* Trip the circuit breaker
8895
* @param fieldName name of the field responsible for tripping the breaker
@@ -127,4 +134,9 @@ public static Type parseValue(String value) {
127134
* @return the name of the breaker
128135
*/
129136
String getName();
137+
138+
/**
139+
* @return whether a tripped circuit breaker will reset itself (transient) or requires manual intervention (permanent).
140+
*/
141+
Durability getDurability();
130142
}

server/src/main/java/org/elasticsearch/common/breaker/CircuitBreakingException.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.elasticsearch.common.breaker;
2020

2121
import org.elasticsearch.ElasticsearchException;
22+
import org.elasticsearch.Version;
2223
import org.elasticsearch.common.io.stream.StreamInput;
2324
import org.elasticsearch.common.io.stream.StreamOutput;
2425
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -33,30 +34,38 @@ public class CircuitBreakingException extends ElasticsearchException {
3334

3435
private final long bytesWanted;
3536
private final long byteLimit;
36-
37-
public CircuitBreakingException(String message) {
38-
super(message);
39-
this.bytesWanted = 0;
40-
this.byteLimit = 0;
41-
}
37+
private final CircuitBreaker.Durability durability;
4238

4339
public CircuitBreakingException(StreamInput in) throws IOException {
4440
super(in);
4541
byteLimit = in.readLong();
4642
bytesWanted = in.readLong();
43+
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
44+
durability = in.readEnum(CircuitBreaker.Durability.class);
45+
} else {
46+
durability = CircuitBreaker.Durability.PERMANENT;
47+
}
4748
}
4849

49-
public CircuitBreakingException(String message, long bytesWanted, long byteLimit) {
50+
public CircuitBreakingException(String message, CircuitBreaker.Durability durability) {
51+
this(message, 0, 0, durability);
52+
}
53+
54+
public CircuitBreakingException(String message, long bytesWanted, long byteLimit, CircuitBreaker.Durability durability) {
5055
super(message);
5156
this.bytesWanted = bytesWanted;
5257
this.byteLimit = byteLimit;
58+
this.durability = durability;
5359
}
5460

5561
@Override
5662
public void writeTo(StreamOutput out) throws IOException {
5763
super.writeTo(out);
5864
out.writeLong(byteLimit);
5965
out.writeLong(bytesWanted);
66+
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
67+
out.writeEnum(durability);
68+
}
6069
}
6170

6271
public long getBytesWanted() {
@@ -67,6 +76,10 @@ public long getByteLimit() {
6776
return this.byteLimit;
6877
}
6978

79+
public CircuitBreaker.Durability getDurability() {
80+
return durability;
81+
}
82+
7083
@Override
7184
public RestStatus status() {
7285
return RestStatus.TOO_MANY_REQUESTS;
@@ -76,5 +89,6 @@ public RestStatus status() {
7689
protected void metadataToXContent(XContentBuilder builder, Params params) throws IOException {
7790
builder.field("bytes_wanted", bytesWanted);
7891
builder.field("bytes_limit", byteLimit);
92+
builder.field("durability", durability);
7993
}
8094
}

server/src/main/java/org/elasticsearch/common/breaker/MemoryCircuitBreaker.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public void circuitBreak(String fieldName, long bytesNeeded) throws CircuitBreak
8484
", which is larger than the limit of [" +
8585
memoryBytesLimit + "/" + new ByteSizeValue(memoryBytesLimit) + "]";
8686
logger.debug("{}", message);
87-
throw new CircuitBreakingException(message, bytesNeeded, memoryBytesLimit);
87+
throw new CircuitBreakingException(message, bytesNeeded, memoryBytesLimit, Durability.PERMANENT);
8888
}
8989

9090
/**
@@ -197,4 +197,9 @@ public long getTrippedCount() {
197197
public String getName() {
198198
return FIELDDATA;
199199
}
200+
201+
@Override
202+
public Durability getDurability() {
203+
return Durability.PERMANENT;
204+
}
200205
}

server/src/main/java/org/elasticsearch/common/breaker/NoopCircuitBreaker.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,9 @@ public long getTrippedCount() {
7171
public String getName() {
7272
return this.name;
7373
}
74+
75+
@Override
76+
public Durability getDurability() {
77+
return Durability.PERMANENT;
78+
}
7479
}

server/src/main/java/org/elasticsearch/indices/breaker/BreakerSettings.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,24 @@
2525
/**
2626
* Settings for a {@link CircuitBreaker}
2727
*/
28-
public class BreakerSettings {
28+
public final class BreakerSettings {
2929

3030
private final String name;
3131
private final long limitBytes;
3232
private final double overhead;
3333
private final CircuitBreaker.Type type;
34+
private final CircuitBreaker.Durability durability;
3435

3536
public BreakerSettings(String name, long limitBytes, double overhead) {
36-
this(name, limitBytes, overhead, CircuitBreaker.Type.MEMORY);
37+
this(name, limitBytes, overhead, CircuitBreaker.Type.MEMORY, CircuitBreaker.Durability.PERMANENT);
3738
}
3839

39-
public BreakerSettings(String name, long limitBytes, double overhead, CircuitBreaker.Type type) {
40+
public BreakerSettings(String name, long limitBytes, double overhead, CircuitBreaker.Type type, CircuitBreaker.Durability durability) {
4041
this.name = name;
4142
this.limitBytes = limitBytes;
4243
this.overhead = overhead;
4344
this.type = type;
45+
this.durability = durability;
4446
}
4547

4648
public String getName() {
@@ -59,10 +61,15 @@ public CircuitBreaker.Type getType() {
5961
return this.type;
6062
}
6163

64+
public CircuitBreaker.Durability getDurability() {
65+
return durability;
66+
}
67+
6268
@Override
6369
public String toString() {
6470
return "[" + this.name +
6571
",type=" + this.type.toString() +
72+
",durability=" + this.durability.toString() +
6673
",limit=" + this.limitBytes + "/" + new ByteSizeValue(this.limitBytes) +
6774
",overhead=" + this.overhead + "]";
6875
}

0 commit comments

Comments
 (0)