Автор оригинала: FreeCodeCamp Community Member.
Этот пост будет использоваться с использованием GraphQL для обработки сервиса, который использует поток ввода/вывода для взаимодействия между клиентом и сервером. В предыдущем посте я издевался на API GraphQL к Универсальный интерфейс шахмат (UCI). UCI использует STDIO Для общения, принимая команды от входного потока и отправки ответов через выходной поток. Я буду использовать UCI как иллюстрацию, но я не буду описывать UCI среди подробностей.
Подземный рыб
Рабочий рыб – это как известной шахматный двигатель, который поддерживает UCI. Использование NODEJS и модуля Stockfish.JS (трансимация JavaScript оригинала), легко настроить рабочий двигатель, который реализует UCI через STDIO:
- Создание и компакт-диск в папку
npm init.
NPM Install ingroffish
Узел Node_modules/angifish/src/stockfish.js
И оттуда вы можете ввести команды UCI в окне терминала и посмотреть результаты.
Обзор запроса против мутации
Запросы выполняются параллельно. Это не проблема для API бездействий, где каждый запрос вернет один и тот же результат, независимо от порядка, в котором возвращаются результаты. UCI не без гражданства , поэтому команды и результаты должны работать в последовательности. Вот пример взаимодействия между командной строкой «клиентский» и шахматический двигатель:
GUI engine // tell the engine to switch to UCI mode uci // engine identify id name Shredder id author Stefan MK // engine sends the options it can change option name Hash type spin default 1 min 1 max 128 option name NalimovPath type string default option name NalimovCache type spin default 1 min 1 max 32 // the engine has sent all parameters and is ready uciok // now the GUI sets some values in the engine // set hash to 32 MB setoption name Hash value 32 setoption name NalimovCache value 1 setoption name NalimovPath value d:\tb;c\tb // this command and the answer is required here! isready // engine has finished setting up the internal values readyok // now we are ready to go
Ответы двигателя на клиентские команды с отступом. Первый переход состояния – это инициировать протокол UCI, где двигатель отвечает на настройках параметров по умолчанию и Uciok Сигнал, указывающий, что он закончен. На данный момент клиент может настроить параметры. Это вступит в силу только тогда, когда команда ready выпущен. Двигатель отвечает Readyok Когда все варианты установлены. Позже переходы состояния произойдут во время игры и анализа и анализа (не показаны).
Запуск нескольких запросов параллельно может выпускать команды преждевременно, поскольку никакого запроса не ожидает ответа другого запроса. Проблема может быть проиллюстрирована с помощью простых API GraphQL для макета асинхронного обслуживания:
import {makeExecutableSchema} from 'graphql-tools'; const typeDefs = ` type Query { message(id: ID!): String! } type Mutation { message(id: ID!): String! } ` const resolvers = { Query: { message: (_, {id}) => new Promise(resolve => { setTimeout(function() { let message = `response to message ${id}`; console.log(message) resolve(message); }, Math.random() * 10000) }) }, Mutation: { message: (_, {id}) => new Promise(resolve => { setTimeout(function() { let message = `response to message ${id}`; console.log(message) resolve(message); }, Math.random() * 10000) }) } } const schema = makeExecutableSchema({typeDefs, resolvers}); export { schema };
Результаты:
В консоли Windows (нижняя половина) вы можете увидеть, когда ответы были возвращены. Теперь выполните те же запросы через мутацию:
Получение ответа занимает дольше, потому что каждая операция должна закончить до того, как будет вызван следующим.
Что это значит для обертки UCI GraphQL
В предыдущем посте Я дал аргументы, почему GraphQL можно использовать для обертывания UCI. Возможно, самый простой способ сделать это – использовать услугу подписки GraphQl. Это отправит события обратно клиенту через веб-сокет. Команды отправляются через запросы или мутации, и ответы возвращаются как подписанные события.
В случае взаимодействия UCI мутации будут использоваться для обеспечения выполнения команд в ожидаемой последовательности. Перед выполнением команды вы сначала настроили подписку на получение ответа. Используя GraphQL, ответы подписки являются безопасными типами, очень похожие на возвратные значения запроса запроса или мутации.
Клиент вызывает мутации GraphQL для отправки запросов через HTTP, затем получает ответы (если есть) через веб-сокет. Хотя простым реализовать на сервере, Интерфейс на основе сокета неловко для клиента Потому что это многопользовано:
- Подписаться на ожидаемое событие ответа
- Отправить команду через http
- Получите ответ HTTP (подтверждение того, что запрос был получен, а не фактический результат)
- ждут настоящего ответа на прибытие через веб-сокет.
- действовать на ответ
Упрощение взаимодействия клиента-сервера
Давайте классифицируем типы ответов UCI отправляет:
- Один линейный ответ
- Нет ответа
- Многострочная, многокольное отклика с терминатором
(В сторону: можно запустить анализ без определенного времени (бесконечный идти «). Это упадет в соответствии с категорией 2, потому что анализ прибудет на лучшую точку завершения перемещения, либо по истощению, либо останавливаться команда.)
Категория 1 Это простой звонок и ответ, и их можно обрабатывать как простые старые HTTP-запросы GraphQL. Не нужно подписаться на ответ: Resolver может просто вернуть его, когда он прибудет.
Категория 2 Не получает ответа от двигателя, но ответ требуется ответ HTTP. Все, что нужно в этом случае, это признать запрос.
Категория 3 Имеет два подтипа: запросы с многострочными, но фиксированными ответами (например, опция ), а запросы с потоковыми, промежуточными ответами ( GO ). Первый может снова обрабатываться через http, потому что ответ будет предсказуемым и своевременно. Последний имеет разные (возможно, длительное) время завершения, и может отправлять ряд промежуточных ответов, представляющих интерес для клиента, который он хотел бы получить в режиме реального времени Отказ Поскольку мы не можем отправить обратно несколько ответов на HTTP-запрос, этот последний случай не может быть обработан HTTP в одиночку, поэтому интерфейс подписки, как описано выше, все еще уместно.
Несмотря на UCI, являющийся потоковым интерфейсом, оказывается, что для большинства случаев HTTP-ответ/запрос может использоваться для взаимодействия через GraphQL.
Выводы
- Схема GraphQL должна состоять из мутаций, потому что UCI является состоянием, а команды должны выполняться в последовательности
- Для команд категории 1 и 2, HTTP-запрос/ответ проще всего. В конце концов все еще есть потоковое движение, но Reshersers GraphQl создаст резользеры Review uci, специфичный для ожидаемого ответа команды uci, прежде чем отправлять команду на двигатель. Этот слушатель разрешит запрос GraphQL через HTTP, когда ответ прибывает из двигателя. Это делает более легкую работу для клиента.
- Сервер также будет отслеживать состояние UCI, чтобы убедиться, что команды выполняются в правильном контексте. Если клиент пытается выполнить команду до того, как двигатель может обращаться с ним, ошибка состояния HTTP будет возвращена
- Для тех случаев, когда нет ожидаемого ответа от UCI, Resolver GraphQL просто подтверждает, что команда была получена.
- Определенный случай для категории 3 (где есть уверенный и быстрый ответ) HTTP.
- Неопределенный случай, где есть промежуточные ответы перед завершением, можно обрабатывать через веб-розетку. Это, в свою очередь, может быть завернут в службу подписки на график.
Реализация издевательства В значительной степени охватывала основные основы, но этот короткий анализ обеспечивает план для продвижения вперед с реализацией.
Код для этой статьи можно найти здесь .