alibaba / alibaba/Sentinel

ErrorEntryFreeException when multiple Entry (in different threads) under the same AsyncContext | AsyncEntry 下有多个子Entry 时,出现错误

Open
#2,197 0 comments 0 reactions 0 assignees View on GitHub
kind/question
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.