GraphQL 是不是会在失败时取消数据获取?
Posted
技术标签:
【中文标题】GraphQL 是不是会在失败时取消数据获取?【英文标题】:Is GraphQL cancelling data fetching in case of a failure?GraphQL 是否会在失败时取消数据获取? 【发布时间】:2019-11-06 18:07:38 【问题描述】:我试图了解 GraphQL 的 (Java) 实现是否足够智能,如果在执行其中一个提取器期间引发异常,则可以取消计划的数据提取?
例如,我运行一个查询来检索客户的所有订单。假设客户有 100 个订单。这意味着 GraphQL 应该进行 100 次调用以检索每个订单的详细信息,但在执行过程中,其中一个调用失败 - 49 个请求已经成功,第 50 个失败,还有 50 个请求要执行。 GraphQL 将中断正在执行的查询,并立即向客户端返回错误。但它会打剩下的 50 个电话吗?
【问题讨论】:
【参考方案1】:这意味着 GraphQL 应该进行 100 次调用以检索每个订单的详细信息
它必须调用解析器函数 100 次,但这是否意味着 100 次网络调用取决于你。没有什么能阻止您批量加载所有 100 合 1 网络请求(如果 API 允许的话)。
GraphQL 将中断正在执行的查询,并立即向客户端返回错误。
只有当你抛出 AbortExecutionException
时才会发生这种情况,否则下一个节点将正常处理。部分结果是 GraphQL 中的常态。一个错误的列表元素不会阻止所有其他元素的解析。正如Ken Chan noted,规范描述了这种行为。
查询的执行方式在很大程度上掌握在您的手中。如果它都是同步的,并且您使用AbortExecutionException
中断执行,则不会进行进一步的调用。如果您调度异步请求(通过返回 CompletionStage
,例如 CompletableFuture
),Java 中没有通用机制来中断这些任务。当您取消CompletableFuture
时,它会does not interrupt the underlying thread。更疯狂的是,它甚至无法将取消传播到之前的CompletionStage
s。这是一个 Java 问题,根本不是 GraphQL 或 graphql-java 特有的。你必须想出非平凡的机器来实现这一点。一种方法可能是使用Tascalate Concurrent,因为它允许取消传播和线程中断。您仍然需要以一种对中断做出实际反应的方式来执行您的任务。所以大部分工作都在你身上。
【讨论】:
【参考方案2】:不,它将继续进行剩余的 50 次调用,因为规范 here 要求它,第 3c 点:
返回一个列表,其中每个列表项都是调用的结果 CompleteValue(innerType, fields, resultItem, variableValues),其中 resultItem 是结果中的每一项。
但它会向您报告订单50失败及其失败原因。最后,您将获得类似于以下内容的 JSON 响应:
"data" :
"orders" : [
"id" : 1 , ..... ,
"id" : 2 , ..... ,
"id" : 3 , ..... ,
......
]
,
"errors" : [
"message" : "Fail to get this order details due to blablab..." ,
"path" : [ "orders", 50 ]
]
【讨论】:
可能我没有正确表达我的问题。如果 GQL 对整体响应没有任何影响,为什么还要进行剩余的 50 次调用?这些调用只会浪费资源。我看不出与规范的冲突。只是为了确保我清楚:查询是“获取 customerId=123 的所有订单”。它不是“获取所有 orderIds=[1,2,3,4,...] 的详细信息”。以上是关于GraphQL 是不是会在失败时取消数据获取?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Sequelize 从 MySQL 获取数据到 GraphQL 失败
在将 graphql-ws 客户端与 gqlgen golang 服务器连接时,获取到“ws://localhost:7080/query”的 WebSocket 连接失败