Skip to main content

GraphQL Activities

One activity, graphql.subscribe, opens a GraphQL subscription and feeds each payload the server pushes into the running workflow as an event.

It speaks the graphql-transport-ws protocol, so it works with graphql-ws, Apollo Server v3+ and Hasura. For one-off queries and mutations there is no GraphQL activity — post them with http.request, which is all a GraphQL query over HTTP is.

Setup

No configuration and no secret-store integration: authentication is whatever headers the server expects, passed in headers on the WebSocket handshake.

Tokens in headers are visible

Unlike providers that take a *_secret_key, a token placed in headers passes through workflow context and history in plaintext. Keep that in mind for long-lived credentials.

The worker needs the gql package with WebSocket transport.

Defaults

86400 s (1 day) timeout, 1 attempt, heartbeating every 20 s against a 60 s timeout.


graphql.subscribe

Connects, starts the subscription, and relays every payload the server pushes as a workflow event that wait_for receives. It runs until the activity is cancelled.

Input

FieldTypeRequiredDefaultDescription
endpointstryesWebSocket endpoint, e.g. wss://api.example.com/graphql
subscriptionstryesThe GraphQL subscription document
variablesdictnonullVariables bound to the subscription
headersdict[str, str]nonullHandshake headers, typically Authorization
relay_topicstrno"default"Event topic the workflow listens on
relay_event_typestrnonullevent_type stamped on each relayed event
target_workflow_idstrnocurrent workflowWorkflow the events are delivered to

Output

FieldTypeDescription
stoppedboolAlways true

The payloads themselves arrive as events, not in the output.

Relayed event data

Each event's data is the subscription payload as the server sent it — the object under the subscription's root field.

Example

Adapted from the provider's integration test:

- activity:
type: graphql.subscribe
name: start_subscription
async_mode: true
input_data:
endpoint: "wss://api.example.com/graphql"
subscription: |
subscription OnPriceTick($symbol: String!) {
priceTick(symbol: $symbol) { symbol price ts }
}
variables:
symbol: "{{ symbol }}"
headers:
Authorization: "Bearer {{ api_token }}"
relay_topic: graphql.msg
relay_event_type: graphql_payload
target_workflow_id: "{{ __sys_info__['workflow_id'] }}"
retry_policy:
heartbeat_interval_sec: 0.5
heartbeat_timeout_sec: 5
- wait_for:
event_source_topic: graphql.msg
event_type: graphql_payload
timeout_sec: 300
output_name: tick

- transform:
output_data:
- price: "{{ tick['data']['priceTick']['price'] }}"
Start it asynchronously

Without async_mode: true (or a parallel branch) this activity blocks the workflow for a full day. Unlike rabbit.receive, it does not default to async mode.

A dropped connection looks like success

Errors inside the subscriber are logged and end the activity successfully with stopped: true — a dead feed is not reported as a failure, and with max_attempts: 1 there is no retry. If the subscription must stay up, have the workflow notice the absence of events (a wait_for timeout) rather than relying on the activity to fail.

At-most-once delivery

Payloads pushed while the connection is down are never replayed. Do not use a GraphQL subscription as the sole transport for events you cannot afford to miss.

Every payload costs workflow history

On the Temporal runtime each relayed payload is a workflow signal and a history entry, and the engine retains at most 1000 unmatched events per topic.