Отменяет ли GraphQL получение данных в случае сбоя?

Я пытаюсь понять, достаточно ли умна (Java) реализация GraphQL, чтобы отменить запланированную выборку данных, если во время выполнения одного из сборщиков возникает исключение?

Например, я запускаю один запрос для получения всех заказов для клиента. Допустим, у клиента 100 заказов. Это означает, что GraphQL должен сделать 100 вызовов для получения сведений о каждом заказе, но на полпути во время выполнения один из вызовов терпит неудачу — 49 запросов уже выполнены успешно, 50-й — неудачно, еще 50 запросов — в очереди. GraphQL прервет текущее выполнение запроса и немедленно вернет клиенту ошибку. Но сделает ли он оставшиеся 50 вызовов или нет?


person Rado Buransky    schedule 24.06.2019    source источник


Ответы (2)


Это означает, что GraphQL должен сделать 100 вызовов для получения сведений о каждом заказе.

Он должен вызвать функцию распознавателя 100 раз, но означает ли это 100 сетевых вызовов или нет, решать вам. Ничто не мешает вам пакетно загрузить все 100 в 1 сетевой запрос (если это позволяет API).

GraphQL прервет текущее выполнение запроса и немедленно вернет клиенту ошибку.

Это происходит только в том случае, если вы выбросите AbortExecutionException, иначе следующий узел будет обработан как обычно. Частичные результаты являются нормой в GraphQL. Один ошибочный элемент списка не мешает разрешению всех остальных. Как отметил Кен Чан, такое поведение описано в спецификации.

То, как выполняется запрос, во многом зависит от вас. Если все синхронно, и вы прерываете выполнение с помощью AbortExecutionException, то дальнейший вызов не будет выполнен. Если вы отправляете асинхронные запросы (возвращая CompletionStage, например, CompletableFuture), в Java нет общего механизма для прерывания этих задач. Когда вы отменяете CompletableFuture, он не выполняет прервать базовый поток. Что еще более безумно, он не может даже распространить отмену на предыдущие CompletionStages. Это проблема Java, а не GraphQL или graphql-java. Вы должны придумать нетривиальный механизм, чтобы сделать это возможным. Одним из способов может быть использование Tascalate Concurrent, так как это позволяет отмену распространения и прерывание потока. Вам по-прежнему необходимо реализовывать свои задачи таким образом, чтобы реально реагировать на прерывания. Так что основная работа на вас.

person kaqqao    schedule 01.08.2019

Нет, он продолжит выполнять оставшиеся 50 вызовов, поскольку этого требует спецификация здесь, пункт 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 ]  
      }
   ]
}
person Ken Chan    schedule 25.06.2019
comment
Наверное я не правильно сформулировал свой вопрос. Зачем GQL делать эти оставшиеся 50 вызовов, если они никак не повлияют на общий отклик? Эти вызовы будут просто пустой тратой ресурсов. Я не вижу конфликта со спецификацией. Просто чтобы убедиться, что я понятен: запрос получает все заказы для customerId = 123. Невозможно получить информацию обо всех идентификаторах orderIds=[1,2,3,4,...]. - person Rado Buransky; 25.06.2019