Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在带IO(Netty)的场景下,基于本项目有没有什么好的办法能做到跨线程传递对象? #232

Open
hu-chia opened this issue Jan 4, 2021 · 6 comments

Comments

@hu-chia
Copy link

hu-chia commented Jan 4, 2021

其实问题比较简单,就是 像这样的异步调用是否有
除了用TtlRunnable/TtlWrappers修饰回调以外的方法,在回调和外部传递类似MDC的参数?


以上图片来自这段Mermaid代码

sequenceDiagram
    participant u as Controller
    participant c as CompletionStage
    participant n as netty-framework
    participant r as remote

    Note over u: 这里有一个上下文对象Context
    u->>+n: query
    n-->>+r: network
    n->>-c: CompletionStage<?>
    r-->>-n: network
    n-->>c: complete
    c-->>u: thenXxxx
    Note over u: 这里需要访问上面的Context
Loading
@oldratlee
Copy link
Member

oldratlee commented Jan 6, 2021

其实问题比较简单,就是 像这样的异步调用是否有
除了用TtlRunnable/TtlWrappers修饰回调以外的方法,在回调和外部传递类似MDC的参数?

这个 是 NettyTTL的集成。

就像 JDK线程池 集成了 TTL,从而 省去了 每次执行任务时的TtlRunnable/TtlWrappers修饰的操作:


集成 涉及了 对于执行/调度组件(如JDK线程池、Netty) 生命周期的理解,并找到 切入点。

欢迎你一起来挖一下Netty以集成好TTL
这样在Netty使用TTL就简单了 @guyeu ♥️

@hu-chia
Copy link
Author

hu-chia commented Jan 6, 2021

我怀疑在这样的场景中通过修饰底层线程的集成是不太能做到的,考虑到这样的场景:

Runnable runnable = () -> {/* capture then run then restore */};

// 在线程A中给操作注册一个回调
new Thread(() -> client.sendAsync().thenRun(runnable)).start();

// Netty或者其他的类似reactor模型的selector线程收到了响应之后触发回调
eventLoopGroup.execute(() -> runnable.run());

因为触发回调的线程和设置回调的线程是两个线程,因此无法通过修饰底层线程来做到捕获线程本地变量(触发回调的线程无法访问其他线程的线程本地变量),因此只能在设置回调的时候进行包装(这就不仅限于Runnable了,理论上这里的回调有可能是任意对象的任意方法)。

我现在想到的办法是尽可能在每一个设置回调的地方调用TtlWrappersTtlRunnable里的包装方法,其实在业务代码里这样的情景也不太多,比如用的比较多的CompletionStage及其实现,我给它写了一个代理类,然后封装业务中会返回这个类的方法,让它们返回我写的代理类,这样就能覆盖大多数情况。

但我其实并不太确定Java Agent内建这样的修饰逻辑是不是一个好办法,这种类涉及的场景太多了,肯定会有场景不需要这样的修饰。我猜这也是TTLJava Agent没有对Runnable及其子类进行修饰的原因。

@oldratlee
Copy link
Member

oldratlee commented Jan 6, 2021

👍 @guyeu

具体的解决方法的展开要好好想想;
我也想想 😀

PS 相关的 issue:
在Reactor Webclient的场景下,使用TTL MDC不生效 oldratlee/log4j2-ttl-thread-context-map#5


但我其实并不太确定Java Agent内建这样的修饰逻辑是不是一个好办法,这种类涉及的场景太多了,肯定会有场景不需要这样的修饰。我猜这也是TTLJava Agent没有对Runnable及其子类进行修饰的原因。

我想的和你一样,『这种类涉及的场景太多了,肯定会有场景不需要这样的修饰』,即 Overkill 了。
相关『对Runnable及其子类进行修饰』的做法的 更多讨论 参见 Issue:

@malone081021
Copy link

malone081021 commented Feb 8, 2021

static {
    Function<Runnable, Runnable> decorator = task -> {
        return TtlRunnable.get(task);
    };
    Schedulers.onScheduleHook("my-hook", decorator);
}

这种方式能解决 @oldratlee @guyeu

@oldratlee
Copy link
Member

oldratlee commented Jul 29, 2021

static {
    Function<Runnable, Runnable> decorator = task -> {
        return TtlRunnable.get(task);
    };
    Schedulers.onScheduleHook("my-hook", decorator);
}

这种方式能解决 @oldratlee @guyeu

COOL ! ! @malone081021 👍 👏

@guyeu 可以尝试测试验证一下,是不是能帮助解决你的问题 :")

@hu-chia
Copy link
Author

hu-chia commented Jul 29, 2021

@oldratlee 这个已经验证过了,可以缓解部分问题,但由于hook执行和注册回调不一定在同一个线程里,所以没有办法真正解决问题。

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

No branches or pull requests

3 participants