Skip to content

Fix Reactor adapter async-context race in SentinelReactorSubscriber.currentContext#3624

Open
wuwen5 wants to merge 1 commit into
alibaba:1.8from
wuwen5:1.8-fix-race-condition-reactor-adapter
Open

Fix Reactor adapter async-context race in SentinelReactorSubscriber.currentContext#3624
wuwen5 wants to merge 1 commit into
alibaba:1.8from
wuwen5:1.8-fix-race-condition-reactor-adapter

Conversation

@wuwen5
Copy link
Copy Markdown
Contributor

@wuwen5 wuwen5 commented May 22, 2026

Describe what this PR does / why we need it

SentinelReactorSubscriber.currentContext() could throw NullPointerException: value under concurrent termination because it read currentEntry.getAsyncContext() twice. If AsyncEntry.exit() cleared async context between those reads, Context.put(...) received null.

  • Race fix in context propagation

    • Updated currentContext() to use the already-captured local sentinelContext when putting Sentinel context into Reactor Context.
    • This removes the check-then-act race window created by re-reading currentEntry.getAsyncContext().
  • Targeted regression coverage

    • Added SentinelReactorSubscriberTest in the reactor adapter test module.
    • The test drives a deterministic interleaving where currentContext() captures a non-null async context, a concurrent cancel path exits/clears context, and currentContext() must still propagate the captured value (the pre-fix path would pass null to Context.put).
com.alibaba.csp.sentinel.context.Context sentinelContext = currentEntry.getAsyncContext();
if (sentinelContext == null) {
    return actual.currentContext();
}
return actual.currentContext()
    .put(SentinelReactorConstants.SENTINEL_CONTEXT_KEY, sentinelContext);
26-05-21 09:28:59.436  WARN [x-server,,,TID:N/A] 766243 --- [ventExecutorLoop-1-4] [i.n.u.c.SingleThreadEventExecutor       :1002] [                 run] : Unexpected exception from an event executor:
java.lang.NullPointerException: value
        at java.util.Objects.requireNonNull(Objects.java:228)
        at reactor.util.context.Context5.put(Context5.java:61)
        at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.currentContext(SentinelReactorSubscriber.java:70)
        at com.alibaba.csp.sentinel.adapter.reactor.InheritableBaseSubscriber.onError(InheritableBaseSubscriber.java:169)
        at com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorSubscriber.onError(SentinelReactorSubscriber.java:37)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
        at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onError(FluxOnAssembly.java:544)
        at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onError(FluxDoFinally.java:119)
        at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:192)
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:259)
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278)
        at reactor.core.publisher.FluxDoFinally$DoFinallySubscriber.onError(FluxDoFinally.java:119)
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222)
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:278)
        at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:258)
        at org.springframework.http.server.reactive.ChannelSendOperator$WriteCompletionBarrier.onError(ChannelSendOperator.java:418)

某Redis Reactive请求先发生异常
→ Reactor进入onError链路
→ SentinelReactorSubscriber.currentContext()
→ Context.put(null)
→ NullPointerException
→ 未捕获异常打穿Netty EventExecutor
→ lettuce-eventExecutorLoop-1-4 号线程死亡(threadStatus=2)
→ executor terminated
→ 后续Redis Reactive callback无法调度
→ Spring Session Reactive Pipeline部分卡死 (重启恢复)

Does this pull request fix one issue?

fixed #3556 #1907

This pull request was created from Copilot chat.

…currentContext` (#1)

* Initial plan

* fix(reactor): avoid async context race in currentContext and add regression test

Agent-Logs-Url: https://github.com/wuwen5/Sentinel/sessions/1d7e9bbc-a643-4695-a906-b0575add87f0

Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wuwen5 <5037807+wuwen5@users.noreply.github.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] springcloud-gateway sentinel 1.8.6版本报空指针异常

3 participants