Концепции
GraphQL
Нагрузочное тестирование GraphQL — запросы и мутации с валидацией по схеме, GraphQL-семантика ошибок и метрики по операциям
Обзор
perfscale нагружает GraphQL-эндпоинты: одна операция на шаг, запросы и мутации через HTTP POST (или GET по желанию), и каждый документ валидируется против схемы самого эндпоинта ещё до отправки.
GraphQL — часть open-source движка: действие std/graphql@v1 доступно на
любом плане. Никакого кодогена и клиентских заглушек: документ — обычный
текст в YAML (или файл .graphql), переменные — JSON, а ответы приходят как
структурированные data/errors, из которых следующие шаги извлекают
значения через интерполяцию ${{ … }}.
Действие: std/graphql@v1
steps:
- name: fetch viewer
use: std/graphql@v1
with:
url: https://api.example.com/graphql
query: |
query GetViewer($id: ID!) {
viewer(id: $id) { id name }
}
variables: { "id": "${{ vars.viewer_id }}" }
check:
status: 200
outputs: viewer
- name: rename widget
use: std/graphql@v1
with:
url: https://api.example.com/graphql
query: |
mutation Rename($id: ID!, $name: String!) {
renameWidget(id: $id, name: $name) { id }
}
variables: { "id": "${{ viewer.data.viewer.id }}", "name": "w-${seq}" }
Параметры
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
url | string | обязателен | GraphQL-эндпоинт, например https://api.example.com/graphql |
query | string | одно из query/query_file | GraphQL-документ прямо в YAML |
query_file | string (путь) | одно из query/query_file | Читать документ из файла .graphql. Доступ к файловой системе: требует allow_file_actions, соблюдает fs_root |
variables | object | — | Переменные запроса. Работает интерполяция ${{ … }}, а токены-генераторы ${…} (${uuid}, ${rand}, ${now}) раскрываются на каждое выполнение |
operation | string | — | operationName для выполнения. Обязателен, если в документе несколько операций; он же — тег метрик по операциям |
method | string | POST | POST (JSON-тело) или GET (query-параметры URL — для кэшируемых через CDN чтений) |
headers | object | — | { "Name": "Value" }, только строковые значения |
timeout | integer (мс) | 10000 | Таймаут на запрос |
insecure | boolean | false | Пропустить проверку TLS-сертификата |
introspection | boolean | true | Один раз за прогон получить схему эндпоинта и валидировать каждый запрос перед отправкой. При неудаче — прогон без валидации (логируется один раз) |
schema_file | string (путь) | — | Валидировать по локальному SDL-файлу вместо интроспекции (запасной вариант для эндпоинтов с выключенной интроспекцией). Файловые правила те же, что у query_file |
pool | string | per-vu | per-vu закрепляет шаг за HTTP-клиентом своего VU (поведение std/http@v1); shared сажает все VU на один общий клиент процесса |
Выход
Доступен через outputs / __last__:
{
"status": 200,
"data": { "viewer": { "id": "u-1" } },
"errors": [ { "message": "widgets timed out" } ],
"body": "{\"data\":…}",
"duration_ms": 12.31,
"headers": { "content-type": "application/json" }
}
data и errors — раскодированный GraphQL-ответ (errors присутствует
только если сервер его прислал); body хранит сырой текст для проверок
body_contains. Извлечение читает структурированный ответ:
${{ create.data.createWidget.id }}.
Валидация по схеме
Каждый запрос парсится до отправки и — когда схема доступна — валидируется по
ней. Опечатка роняет шаг (и perfscale lint) с подсказкой «может, вы имели в
виду», вместо того чтобы жечь запросы в цель:
fetch viewer: query validation failed: unknown field 'viewr' on type 'Query' — did you mean 'viewer'?
Два источника схемы:
- Интроспекция (по умолчанию) — движок один раз за прогон отправляет интроспекционный запрос, кэширует схему на весь процесс и валидирует по ней каждый запрос. Один сетевой раунд на эндпоинт, сколько бы ни было VU.
schema_file: schema.graphql— валидация по локальному SDL-файлу. Запасной вариант для эндпоинтов, где интроспекция выключена (обычное дело в проде): если интроспекция не удалась иschema_fileне задан, шаг всё равно выполняется — без валидации, с одной строкой[sys]в логе об этом.introspection: falseотключает получение схемы полностью.
perfscale lint применяет тот же контроль: синтаксис — всегда (офлайн),
схему — когда эндпоинт доступен или задан SDL-файл. perfscale lint --offline пропускает сетевой проход.
Что считается ошибкой
GraphQL-ошибки приезжают в теле 200 OK, поэтому HTTP-статус сам по себе не
вердикт:
- HTTP-статус ≥ 400 → шаг падает.
- Есть
errors, аdatanull или отсутствует → шаг падает (не разрешилось ничего). - Частичный
dataплюсerrors→ шаг проходит — сервер разрешил, что смог, — а ошибки учитываются вgraphql_errors.
Синтаксическая ошибка, провал валидации по схеме или нечитаемый query_file
роняют шаг до любого запроса — цель никогда не увидит битый документ.
Стандартные проверки check: работают без изменений: status,
duration_ms_lt, body_contains (по сырому телу).
Метрики
graphql_req_duration— гистограмма времени каждой операции; раннер выводит из неёgraphql_req_failed(rate). Гейт черезstd/thresholds@v1:"graphql_req_duration": ["p99<200"].graphql_errors— счётчик GraphQL-ошибок, включая те, что пришли с частичными данными и не уронили шаг.graphql_op_<operationName>_duration— гистограмма по операции; пишется только когда операция именована (явныйoperationили единственная именованная операция), так что кардинальность метрик ограничена самим определением теста.- Запрос также питает стандартные агрегаты
http_req_duration/http_req_failed/http_reqs, как любой HTTP-шаг.
Пул соединений
pool: per-vu (по умолчанию) закрепляет шаг за HTTP-клиентом своего VU — то
же keep-alive-поведение, что у std/http@v1: VU переиспользует свои тёплые
соединения между итерациями. pool: shared сажает все VU на один общий
клиент процесса: максимальное переиспользование соединений к одному
эндпоинту ценой конкуренции за блокировку пула при очень больших числах VU.
Ограничения
- Подписки не поддерживаются (транспорт — HTTP запрос/ответ); документ с подпиской не проходит валидацию.
- Батчинг запросов (массивы операций) и инкрементальная доставка
(
@defer/@stream) не поддерживаются — одна операция на шаг. query_fileиschema_file— доступ к файловой системе: требуютallow_file_actionsв конфиге прогона и соблюдают ограничениеfs_root.
Дальше
- GraphQL из CLI — путь от YAML до сводки метрик.
examples/graphql.test.yaml— готовый к запуску сценарий в OSS-репозитории.