G
N
I
D
A
O
L

写书写到一半,强迫症发作跑去给HotChocolate修bug

前言

这是写作《C#与.NET6 开发从入门到实践》时的小故事,作为本书正式上市的宣传,在此分享给大家。

正文

.NET目前有两个比较成熟的GraphQL框架,其中一个是HotChocolate,在使用对比后认为这个使用更方便,因此将其作为本书的介绍内容。结果在研究客户端订阅的时候发现一个bug:如果订阅因为异常(例如网络掉线)而结束,订阅不会有任何反应(只是这个订阅永远不会再收到数据)。我就在想,如果一个订阅长时间没有收到数据,到底是因为出问题了还是只是单纯的没有新数据。

随后我就跑到GitHub上提交问题,结果作者并没有理解我的意思,然后就不了了之。最后在准备实战演练的项目时又用到了客户端,又想起来这个bug,就当场强迫症发作又给作者提问题,结果又是石沉大海。无奈干脆下载代码亲自研究客户端到底是哪里出问题导致这个bug。感兴趣的朋友可以看看https://github.com/ChilliCream/graphql-platform/issues/5006

这里我就简单介绍一下问题的原因和处理方法。客户端在WebSocket和订阅实例之间使用Pipeline作为中介,然后使用Channel向用户API传递解析后的对象。其中数据读取和写入使用两个Task分别负责,读取WebSocket写入Pipeline的Task在循环读取WebSocket的时候没有向Channel传递表示连接结束的对象,导致客户端实例不知道实情,最后用户API没有任何反。用户API中使用的IObserver也是一个关键点,客户端在订阅异常结束时没有调用Complete方法通知观察者数据流已经结束,导致用户API没有反应。根据微软文档,应该在确定数据流结束后调用Complete方法通知观察者结束观察,无论数据流因何结束。

客户端使用的Pipeline是一个网络数据缓存的优秀中介,手动处理粘包数据是非常麻烦的,Pipeline就专门负责管理数据是否被消耗,查看过但没有被消耗的数据应该如何处理。新的Span和Memory类型则可以实现直接访问缓冲区内存,避免查看但不消耗数据的情况下反复复制内存导致性能下降和内存占用上升。

结果作者在使用Pipeline之后切断了WebSocket和用户API之间的直接联系又没有处理相关情况最后导致了这个bug。目前作者正在考虑改用其他方式实现客户端,这个问题也许会自然消失。我的修复已经合并到主分支,不过被标记到13.0上,但是客户端目前12.0和13.0的包共存,12.0的代码生成器生成的代码和13.0的实现不兼容。不知道12.0版有没有包含修复。

结语

这个问题前前后后历时将近半年,真是把我折磨的够呛。最后请让我再宣传一次我的新书《C#与.NET6 开发从入门到实践》。详情请看《C#与.NET6 开发从入门到实践》上市,作者亲自来打广告了!

QQ群

读者交流QQ群:540719365
image

欢迎读者和广大朋友一起交流,如发现本书错误也欢迎通过博客园、QQ群等方式告知我。

购买方式:
京东自营:https://item.jd.com/13860498.html
当当自营:https://product.dangdang.com/29546824.html

本文地址:https://www.cnblogs.com/coredx/p/17253035.html

posted @ 2023-03-24 18:32  coredx  阅读(437)  评论(2编辑  收藏  举报