ErrorEntryFreeException when multiple Entry (in different threads) under the same AsyncContext | AsyncEntry 下有多个子Entry 时,出现错误
- Dominant language
- Java
- Stars
- 23.1k
- Forks
- 8.1k
- PR merge metrics
- No merged PRs in 30d
Description
## 问题描述
sentinel版本:1.6.3, 当一个AsyncEntry 下挂有多个子Entry类型时,报错,代码以及错误信息如下:
### 代码
```java
public class SentinelExample {
static List getFlowRules() {
FlowRule flowRuleTest = new FlowRule();
flowRuleTest.setClusterMode(false)
.setCount(5d)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER)
.setWarmUpPeriodSec(10)
.setLimitApp("default")
.setResource("test");
FlowRule flowRuleTest1 = new FlowRule();
flowRuleTest1.setClusterMode(false)
.setCount(3d)
.setGrade(RuleConstant.FLOW_GRADE_QPS)
.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)
.setWarmUpPeriodSec(10)
.setLimitApp("default")
.setResource("test1");
return Lists.newArrayList(flowRuleTest, flowRuleTest1);
}
public static void main(String[] args) throws BlockException {
System.setProperty(RecordLog.LOG_OUTPUT_TYPE, RecordLog.LOG_OUTPUT_TYPE_CONSOLE);
System.setProperty(RecordLog.LOG_DIR, Paths.get("./metric_log").toFile().getAbsolutePath());
SentinelProperty> property = new DynamicSentinelProperty<>();
property.addListener(new PropertyListener>() {
@Override
public void configUpdate(List value) {
System.out.println("更新规则");
}
@Override
public void configLoad(List value) {
System.out.println("重新加载规则");
}
});
FlowRuleManager.register2Property(property);
FlowRuleManager.loadRules(getFlowRules());
AsyncEntry rootEntry = SphU.asyncEntry("ROOT");
new Thread(() -> ContextUtil.runOnContext(rootEntry.getAsyncContext(), () -> {
for (; ; ) {
try (Entry entry = SphU.entry("test")) {
System.out.println("Test执行时间");
} catch (BlockException e) {
System.out.println("Test阻塞");
}
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
})).start();
new Thread(() -> ContextUtil.runOnContext(rootEntry.getAsyncContext(), () -> {
for (; ; ) {
try (Entry entry = SphU.entry("test1")) {
System.out.println("Test1执行时间");
} catch (BlockException e) {
System.out.println("Test1阻塞");
}
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
})).start();
}
}
```
### 错误信息
```
java.lang.NullPointerException
at com.alibaba.csp.sentinel.slots.statistic.StatisticSlot.exit(StatisticSlot.java:143)
at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireExit(AbstractLinkedProcessorSlot.java:46)
at com.alibaba.csp.sentinel.slots.logger.LogSlot.exit(LogSlot.java:49)
at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireExit(AbstractLinkedProcessorSlot.java:46)
at com.alibaba.csp.sentinel.slots.clusterbuilder.ClusterBuilderSlot.exit(ClusterBuilderSlot.java:106)
at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireExit(AbstractLinkedProcessorSlot.java:46)
at com.alibaba.csp.sentinel.slots.nodeselector.NodeSelectorSlot.exit(NodeSelectorSlot.java:175)
at com.alibaba.csp.sentinel.slotchain.AbstractLinkedProcessorSlot.fireExit(AbstractLinkedProcessorSlot.java:46)
at com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain$1.exit(DefaultProcessorSlotChain.java:36)
at com.alibaba.csp.sentinel.slotchain.DefaultProcessorSlotChain.exit(DefaultProcessorSlotChain.java:80)
at com.alibaba.csp.sentinel.CtEntry.exitForContext(CtEntry.java:83)
at com.alibaba.csp.sentinel.CtEntry.trueExit(CtEntry.java:108)
at com.alibaba.csp.sentinel.CtEntry.exit(CtEntry.java:61)
at com.alibaba.csp.sentinel.CtEntry.exitForContext(CtEntry.java:75)
at com.alibaba.csp.sentinel.CtEntry.trueExit(CtEntry.java:108)
at com.alibaba.csp.sentinel.CtEntry.exit(CtEntry.java:61)
at com.alibaba.csp.sentinel.Entry.exit(Entry.java:79)
at com.alibaba.csp.sentinel.Entry.close(Entry.java:93)
at com.example.sentinel.SentinelExample.lambda$null$2(SentinelExample.java:97)
at com.alibaba.csp.sentinel.context.ContextUtil.runOnContext(ContextUtil.java:276)
at com.example.sentinel.SentinelExample.lambda$main$3(SentinelExample.java:91)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-5" com.alibaba.csp.sentinel.ErrorEntryFreeException: The order of entry exit can't be paired with the order of entry, current entry in context: , but expected:
at com.alibaba.csp.sentinel.CtEntry.exitForContext(CtEntry.java:80)
at com.alibaba.csp.sentinel.CtEntry.trueExit(CtEntry.java:108)
at com.alibaba.csp.sentinel.CtEntry.exit(CtEntry.java:61)
at com.alibaba.csp.sentinel.Entry.exit(Entry.java:79)
at com.alibaba.csp.sentinel.Entry.close(Entry.java:93)
at com.example.sentinel.SentinelExample.lambda$null$2(SentinelExample.java:97)
at com.alibaba.csp.sentinel.context.ContextUtil.runOnContext(ContextUtil.java:276)
at com.example.sentinel.SentinelExample.lambda$main$3(SentinelExample.java:91)
at java.lang.Thread.run(Thread.java:745)
```
### 问题
为什么提示我的Runnable 空指针? 明明已经创建了该对象
Contributor guide
Research direction
Start with the provided two-thread reproduction, then read CtEntry.exitForContext and StatisticSlot.exit along the stack trace to understand how entries sharing an AsyncContext are paired. Check whether the concurrent exits explain both the NullPointerException and ErrorEntryFreeException; done means the reproduction completes without either failure, with regression coverage if the repository has a suitable test location.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100