|
|
@@ -15,7 +15,6 @@ |
|
|
|
*/ |
|
|
|
package com.alibaba.csp.sentinel; |
|
|
|
|
|
|
|
import java.util.Iterator; |
|
|
|
import java.util.LinkedList; |
|
|
|
|
|
|
|
import com.alibaba.csp.sentinel.context.Context; |
|
|
@@ -41,7 +40,6 @@ class CtEntry extends Entry { |
|
|
|
protected ProcessorSlot<Object> chain; |
|
|
|
protected Context context; |
|
|
|
protected LinkedList<BiConsumer<Context, Entry>> exitHandlers; |
|
|
|
|
|
|
|
|
|
|
|
CtEntry(ResourceWrapper resourceWrapper, ProcessorSlot<Object> chain, Context context) { |
|
|
|
super(resourceWrapper); |
|
|
@@ -58,7 +56,7 @@ class CtEntry extends Entry { |
|
|
|
} |
|
|
|
this.parent = context.getCurEntry(); |
|
|
|
if (parent != null) { |
|
|
|
((CtEntry)parent).child = this; |
|
|
|
((CtEntry) parent).child = this; |
|
|
|
} |
|
|
|
context.setCurEntry(this); |
|
|
|
} |
|
|
@@ -68,31 +66,55 @@ 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(); |
|
|
|
CtEntry e = (CtEntry) context.getCurEntry(); |
|
|
|
while (e != null) { |
|
|
|
e.exit(count, args); |
|
|
|
e = (CtEntry)e.parent; |
|
|
|
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) { |
|
|
|
((CtEntry)parent).child = null; |
|
|
|
((CtEntry) parent).child = null; |
|
|
|
} |
|
|
|
if (parent == null) { |
|
|
|
// Default context (auto entered) will be exited automatically. |
|
|
@@ -109,32 +131,18 @@ class CtEntry extends Entry { |
|
|
|
protected void clearEntryContext() { |
|
|
|
this.context = null; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@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; |
|
|
|
} |
|
|
|