Refactor exit handler mechanism of Entry
- Rename: whenComplete -> whenTerminate - Execute the exit handler directly after the onExit hook of all slots Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
55e038cc33
commit
dae4621e6e
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package com.alibaba.csp.sentinel;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.alibaba.csp.sentinel.context.Context;
|
||||
|
|
@ -42,7 +41,6 @@ class CtEntry extends Entry {
|
|||
protected Context context;
|
||||
protected LinkedList<BiConsumer<Context, Entry>> exitHandlers;
|
||||
|
||||
|
||||
CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) {
|
||||
super(resourceWrapper);
|
||||
this.chain = chain;
|
||||
|
|
@ -68,14 +66,33 @@ class CtEntry extends Entry {
|
|||
trueExit(count, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: the exit handlers will be called AFTER onExit of slot chain.
|
||||
*/
|
||||
private void callExitHandlersAndCleanUp(Context ctx) {
|
||||
if (exitHandlers != null && !exitHandlers.isEmpty()) {
|
||||
for (BiConsumer<Context, Entry> handler : this.exitHandlers) {
|
||||
try {
|
||||
handler.accept(ctx, this);
|
||||
} catch (Exception e) {
|
||||
RecordLog.warn("Error occurred when invoking entry exit handler, current entry: "
|
||||
+ resourceWrapper.getName(), e);
|
||||
}
|
||||
}
|
||||
exitHandlers = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void exitForContext(Context context, int count, Object... args) throws ErrorEntryFreeException {
|
||||
if (context != null) {
|
||||
// Null context should exit without clean-up.
|
||||
if (context instanceof NullContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getCurEntry() != this) {
|
||||
String curEntryNameInContext = context.getCurEntry() == null ? null : context.getCurEntry().getResourceWrapper().getName();
|
||||
String curEntryNameInContext = context.getCurEntry() == null ? null
|
||||
: context.getCurEntry().getResourceWrapper().getName();
|
||||
// Clean previous call stack.
|
||||
CtEntry e = (CtEntry) context.getCurEntry();
|
||||
while (e != null) {
|
||||
|
|
@ -83,12 +100,17 @@ class CtEntry extends Entry {
|
|||
e = (CtEntry) e.parent;
|
||||
}
|
||||
String errorMessage = String.format("The order of entry exit can't be paired with the order of entry"
|
||||
+ ", current entry in context: <%s>, but expected: <%s>", curEntryNameInContext, resourceWrapper.getName());
|
||||
+ ", current entry in context: <%s>, but expected: <%s>", curEntryNameInContext,
|
||||
resourceWrapper.getName());
|
||||
throw new ErrorEntryFreeException(errorMessage);
|
||||
} else {
|
||||
// Go through the onExit hook of all slots.
|
||||
if (chain != null) {
|
||||
chain.exit(context, resourceWrapper, count, args);
|
||||
}
|
||||
// Go through the existing terminate handlers (associated to this invocation).
|
||||
callExitHandlersAndCleanUp(context);
|
||||
|
||||
// Restore the call stack.
|
||||
context.setCurEntry(parent);
|
||||
if (parent != null) {
|
||||
|
|
@ -111,31 +133,17 @@ class CtEntry extends Entry {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void whenComplete(BiConsumer<Context, Entry> consumer) {
|
||||
public void whenTerminate(BiConsumer<Context, Entry> handler) {
|
||||
if (this.exitHandlers == null) {
|
||||
this.exitHandlers = new LinkedList<>();
|
||||
}
|
||||
this.exitHandlers.add(consumer);
|
||||
this.exitHandlers.add(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Entry trueExit(int count, Object... args) throws ErrorEntryFreeException {
|
||||
exitForContext(context, count, args);
|
||||
|
||||
if (this.exitHandlers != null) {
|
||||
Iterator<BiConsumer<Context, Entry>> it = this.exitHandlers.iterator();
|
||||
BiConsumer<Context, Entry> cur;
|
||||
while (it.hasNext()) {
|
||||
cur = it.next();
|
||||
try {
|
||||
cur.accept(this.context, this);
|
||||
} catch (Exception e) {
|
||||
RecordLog.warn("Error invoking exit handler", e);
|
||||
}
|
||||
}
|
||||
this.exitHandlers = null;
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -180,12 +180,13 @@ public abstract class Entry implements AutoCloseable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Like `CompletableFuture` since JDK8 it guarantees specified consumer
|
||||
* is invoked when this entry exited.
|
||||
* Like {@code CompletableFuture} since JDK 8, it guarantees specified handler
|
||||
* is invoked when this entry terminated (exited), no matter it's blocked or permitted.
|
||||
* Use it when you did some STATEFUL operations on entries.
|
||||
*
|
||||
* @param consumer
|
||||
* @param handler handler function on the invocation terminates
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public abstract void whenComplete(BiConsumer<Context, Entry> consumer);
|
||||
public abstract void whenTerminate(BiConsumer<Context, Entry> handler);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public abstract class AbstractCircuitBreaker implements CircuitBreaker {
|
|||
if (currentState.compareAndSet(State.OPEN, State.HALF_OPEN)) {
|
||||
notifyObservers(State.OPEN, State.HALF_OPEN, null);
|
||||
Entry entry = context.getCurEntry();
|
||||
entry.whenComplete(new BiConsumer<Context, Entry>() {
|
||||
entry.whenTerminate(new BiConsumer<Context, Entry>() {
|
||||
@Override
|
||||
public void accept(Context context, Entry entry) {
|
||||
// Note: This works as a temporary workaround for https://github.com/alibaba/Sentinel/issues/1638
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class EntryTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void whenComplete(BiConsumer<Context, Entry> consumer) {
|
||||
public void whenTerminate(BiConsumer<Context, Entry> consumer) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue