微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

GraphQL-Java上的ThreadLocals

如何解决GraphQL-Java上的ThreadLocals

我要在GraphQL上公开一个旧版Web应用程序,但是该Web应用程序使用Threadlocals(以及其他Apache-Shiro)。

由于GraphQL-java似乎正在使用fork-join pool进行并发,所以我担心我需要走多远才能确保ThreadLocals仍能正常工作和安全地工作。

在阅读文档和源代码后,似乎并发很大一部分是由返回CompletableFuture的DataFetchers实现的,我无法确定这是否是唯一的并发源(我认为不是),并且DataFetchers本身是否从fork-join pool

调用

那么将我的DataFetcher包裹在设置并清除ThreadLocals的委托中是否安全?还是仍然有被抢占并继续在fork-join pool中的另一个线程上运行的风险,例如:

static class WrappedDataFetcher implements DataFetcher<Object> {
        private DataFetcher<?> realDataFetcher;

        WrappedDataFetcher(DataFetcher<?> realDataFetcher) {
            this.realDataFetcher = realDataFetcher;
        }

        @Override
        public Object get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
            try {
                setThreadLocalsFromrequestOrContext(dataFetchingEnvironment);
                return realDataFetcher.get(dataFetchingEnvironment);
            } finally {
                clearTreadLocals();
            }
        }
    }

还是我需要像这样在Threadpool中显式运行DataFetchers:

    static class WrappedDataFetcherThreadPool implements DataFetcher<Object> {
        private DataFetcher<?> wrappedDataFetcher;
        private ThreadPoolExecutor executor;


        WrappedDataFetcherThreadPool(DataFetcher<?> realDataFetcher,ThreadPoolExecutor executor) {
            // Wrap in Wrapper from prevIoUs example to ensure threadlocals in the executor
            this.wrappedDataFetcher = new WrappedDataFetcher(realDataFetcher);
            this.executor = executor;
        }

        @Override
        public Object get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception {
            Future<?> future = executor.submit(() -> wrappedDataFetcher.get(dataFetchingEnvironment));
            return future.get(); //for simplicity / clarity of the question
        }
    }

我认为第二个解决了我的问题,但感觉像是过分杀了,我担心性能。但是我认为第一个有先发制人的风险。

如果有更好的方法来处理此问题,我也希望听到。

注意:这与GraphQL的异步特性无关(我希望也能利用它),而是与通过fork-join pool可能在请求之间混淆的用footLocals运行多个请求的可能的副作用有关。

解决方法

据我所知,graphql-java不使用其自己的线程池,而是依赖于应用程序。它使用将来的回调实现它的方式。说这是应用程序的当前状态。

具有线程本地存储TLS_1的线程T_1执行数据提取器DF_1。

Graphql-java引擎将同步回调附加到DF_1返回的将来。如果未返回future,则将结果包装在完整的future中,然后附加同步回调。由于回调是同步的,将来完成的线程将运行该回调。如果除T_1之外的任何其他线程完成了将来,则TLS_1将会丢失(除非将其复制到执行线程中)。一个示例是无阻塞HTTP I / O库,该库使用I / O线程来完成将来的响应。

在此链接中,作者对graphql-java库中的线程行为发表了更多评论

https://spectrum.chat/graphql-java/general/how-to-supply-custom-executor-service-for-data-fetchers-to-run-on~29caa730-9114-4883-ab4a-e9700f225f93

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。