Есть два распространенных способа получить живые данные с сервера GraphQL: подписки и живые запросы. Подписка выглядит так:

subscription {
  eventX {
    selection
  }
}

Live Query выглядит так:

@live
query {
  selection
}

В чем разница между подписками и интерактивными запросами? Когда бы вы использовали одно против другого? Давайте сравним подписки и интерактивные запросы теоретически и на примерах.

Сходства

Предсказуемый поток ответа: Да

Оба являются операциями запроса / потока, когда сервер отвечает на запрос клиента потоком ответов GraphQL в форме, указанной в документе запроса клиента. Одно предостережение: некоторые реализации Live Query отправляют различия вместо всей полезной нагрузки.

Гибкий транспорт / протокол: Да

Оба могут использовать различные комбинации транспорта / протокола.

Примеры транспортов: TCP, WebSocket, UDP, SSE, HTTP Long-polling.

Примеры протоколов: MQTT, Socket.io, Redis, AMQP, RSocket.

Мы намеренно оставили это открытым в спецификации, потому что транспорты неизбежно будут различаться в разных организациях и сценариях использования. Однако маловероятно, что конкретная комбинация транспорта / протокола будет обслуживать только одну операцию, а не другую.

Сервер с отслеживанием состояния и реактивная инфраструктура: Да

Для подписки нам нужна какая-то система pubsub. Для систем Live Query, которые перерастают в опрос, нам нужны реактивные источники данных (например, база данных, которая позволяет настраивать запрос) и сопутствующая модель программирования (например, Rx). В обоих случаях серверу необходимо хранить каждый запрос на выполнение операции, подписываться на базовые исходные потоки и поддерживать индекс долгоживущих соединений с клиентом. Короче говоря, вам понадобится какой-то шлюз реального времени. Сервер также отвечает за освобождение памяти / соединений для каждого клиента, когда клиент отключается.

Гарантированно, под заказ, точно один раз: Нет

Ни одна из операций не включает ограничений или гарантий нефункциональных возможностей сетевой доставки, таких как гарантированная доставка по порядку (хотя TCP обеспечивает их на транспортном уровне). Например, если вы реализуете поток ответов GraphQL через UDP, и полезная нагрузка ответа отбрасывается при передаче, то выбор повторной отправки отброшенной полезной нагрузки не зависит от типа операции.

Буферизация, регулирование: нет

Любое долгоживущее соединение подвержено сбоям. Для таких случаев использования, как история чата, важно повторно синхронизировать состояние между клиентом и сервером после отключения. Иногда этого можно достичь, обнаружив отключение на сервере, буферизовав полезные данные во время и воспроизведя их, когда клиент вернется в оперативный режим. В других случаях сервер может завалить клиента слишком большим объемом данных; клиент и сервер могут согласиться на какой-то протокол управления потоком.

Обе эти общие функции могут поддерживаться или игнорироваться независимо от типа операции и даже внутри типов операций. Например, предположим, что у вас есть две подписки:

subscription a { 
  superImportantMessage {
    message
  }
}
subscription b { 
  poke {
    poke
  }
}

Сервер может поддерживать автономную буферизацию для одной из этих подписок, но не для другой. Это совершенно верно, и мы не должны фиксировать это в спецификации.

Отличия

Прямая трансляция «По запросу»

Вы можете превратить обычный запрос в живой запрос, добавив указанную директиву live. И наоборот, вы можете игнорировать директиву live и обрабатывать живой запрос как обычный запрос. Например, если сервер WebSocket недоступен, вы можете прибегнуть к опросу запроса через HTTP. Напротив, операция подписки не может быть опрошена и не может переключаться между режимами реального времени и запроса / ответа. Лично я считаю, что это суперсила Live Queries.

Технические характеристики

Подписки - это операции GraphQL, определенные в спецификации. Динамические запросы официально не определены в спецификации. Скорее, они обозначаются специальной директивой для операции запроса. Конкретная директива может различаться в зависимости от реализации, например: @live, @fb_live, @live_query.

Декларация и Клиентский договор

Подписки наблюдают за событиями, Live Queries наблюдают за данными. Клиенты могут указать операцию подписки с помощью ключевого слова операции подписки:

subscription {
  eventX {
    selection
  }
}

Когда мы выполняем описанную выше операцию, мы говорим серверу: «всякий раз, когда происходит событие X, выполните selection и отправьте мне результат».

Чтобы выполнить живой запрос, клиенты должны включить директиву, такую ​​как «@live», предварительно согласованную между клиентом и сервером.

@live
query {
  selection
}

Когда мы выполняем описанную выше операцию, мы говорим серверу: «Оцените [выбор] немедленно, а затем отправьте мне новую полезную нагрузку, когда [выбор] приведет к другому ответу». Другими словами, поток ответов Live Query должен напоминать бесконечно быстрый и дешевый опрос постоянного запроса, отбрасывая повторяющиеся ответы.

Зрелость в масштабе

Facebook разработал подписку GraphQL внутри компании с 2015 года и использовал ее для поддержки глобальных функций, таких как живые комментарии и потоковые реакции. Поддержка Live Queries появилась позже и, насколько мне известно, никогда не достигала того же масштаба, что и подписки. В зрелых организациях за пределами Facebook, например, в AppSync, Apollo и Prisma, также, похоже, больше опыта работы с подписками в масштабе, чем с Live Queries. Конечно, со временем это может измениться.

Служба поддержки

Существует множество библиотек и сервисов, поддерживающих подписки GraphQL, например, вышеупомянутый AWS AppSync. Hasura поддерживает как подписки, так и живые запросы, а клиент Apollo может приблизить поведение живого запроса с помощью встроенной функции опроса.

Живые запросы сегодня и завтра

Вы используете Live Queries в производственной среде? Вы не хотите? Стоит ли добавлять в спецификацию Live Queries? Если да, то что о них сказать?