info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
description: 'Triggered when an issue is updated.'
end
end
```
NOTE:
If you are connecting an EE subscription, update `EE::Types::SubscriptionType` instead.
Make sure the `:issue_updated` argument matches the name used in the `subscription` request sent by the frontend in camel-case (`issueUpdated`), or `graphql-ruby` does not know which subscribers to inform. The event can now trigger.
#### Add the new trigger
Skip this step if you can reuse an existing trigger.
We use a facade around `GitlabSchema.subscriptions.trigger` to make it simpler to trigger an event.
Because a push initiated by the server needs to propagate over the network and trigger a view update
in the client without any user interaction whatsoever, real-time features can only be understood
by looking at the entire stack including frontend and backend.
NOTE:
For historic reasons, the controller routes that service updates in response to clients polling
for changes are called `realtime_changes`. They use conditional GET requests and are unrelated
to the real-time behavior covered in this guide.
Any real-time update pushed into a client originates from the GitLab Rails application. We use the following
technologies to initiate and service these updates:
In the GitLab Rails backend:
- Redis PubSub to handle subscription state.
- Action Cable to handle WebSocket connections and data transport.
-`graphql-ruby` to implement GraphQL subscriptions and triggers.
In the GitLab frontend:
- Apollo Client to handle GraphQL requests, routing and caching.
- Vue.js to define and render view components that update in real-time.
The following figure illustrates how data propagates between these layers.
```mermaid
sequenceDiagram
participant V as Vue Component
participant AP as Apollo Client
participant P as Rails/GraphQL
participant AC as Action Cable/GraphQL
participant R as Redis PubSub
AP-->>V: injected
AP->>P: HTTP GET /-/cable
AC-->>P: Hijack TCP connection
AC->>+R: SUBSCRIBE(client)
R-->>-AC: channel subscription
AC-->>AP: HTTP 101: Switching Protocols
par
V->>AP: query(gql)
Note over AP,P: Fetch initial data for this view
AP->>+P: HTTP POST /api/graphql (initial query)
P-->>-AP: initial query response
AP->>AP: cache and/or transform response
AP->>V: trigger update
V->>V: re-render
and
Note over AP,AC: Subscribe to future updates for this view
V->>AP: subscribeToMore(event, gql)
AP->>+AC: WS: subscribe(event, query)
AC->>+R: SUBSCRIBE(event)
R-->>-AC: event subscription
AC-->>-AP: confirm_subscription
end
Note over V,R: time passes
P->>+AC: trigger event
AC->>+R: PUBLISH(event)
R-->>-AC: subscriptions
loop For each subscriber
AC->>AC: run GQL query
AC->>+R: PUBLISH(client, query_result)
R-->>-AC: callback
AC->>-AP: WS: push query result
end
AP->>AP: cache and/or transform response
AP->>V: trigger update
V->>V: re-render
```
In the subsequent sections we explain each element of this stack in detail.
### Action Cable and WebSockets
[Action Cable](https://guides.rubyonrails.org/action_cable_overview.html) is a library that adds
[WebSocket](https://www.rfc-editor.org/rfc/rfc6455) support to Ruby on Rails.
WebSockets were developed as an HTTP-friendly solution to enhance existing HTTP-based servers and
applications with bidirectional communication over a single TCP connection.
A client first sends an ordinary HTTP request to the server, asking it to upgrade the connection
to a WebSocket instead. When successful, the same TCP connection can then be used by both client
and server to send and receive data in either direction.
Because the WebSocket protocol does not prescribe how the transmitted data is encoded or structured,
we need libraries like Action Cable that take care of these concerns. Action Cable:
- Handles the initial connection upgrade from HTTP to the WebSocket protocol. Subsequent requests using
the `ws://` scheme are then handled by the Action Cable server and not Action Pack.
- Defines how data transmitted over the WebSocket is encoded. Action Cable specifies this to be JSON. This allows the
application to provide data as a Ruby Hash and Action Cable (de)serializes it from and to JSON.
- Provides callback hooks to handle clients connecting or disconnecting and client authentication.
- Provides `ActionCable::Channel` as a developer abstraction to implement publish/subscribe and remote procedure calls.
Action Cable supports different implementations to track which client is subscribed to which
`ActionCable::Channel`. At GitLab we use the Redis adapter, which uses
[Redis PubSub](https://redis.io/docs/manual/pubsub/) channels as a distributed message bus.
Shared storage is necessary because different clients might connect to the same Action Cable channel
from different Puma instances.
NOTE:
Do not confuse Action Cable channels with Redis PubSub channels. An Action Cable `Channel` object is a
programming abstraction to classify and handle the various kinds of data going over the WebSocket connection.
In Action Cable, the underlying PubSub channel is referred to as a broadcasting instead and the association
between a client and a broadcasting is called a subscription. In particular, there can be many broadcastings
(PubSub channels) and subscriptions for each Action Cable `Channel`.
Because Action Cable allows us to express different kinds of behavior through its `Channel` API, and because
updates to any `Channel` can use the same WebSocket connection, we only require a single WebSocket connection
to be established for each GitLab page to enhance a view component on that page with real-time behavior.
To implement real-time updates on a GitLab page, we do not write individual `Channel` implementations.
Instead, we provide the `GraphqlChannel` to which all pages that require push-based updates on GitLab
subscribe.
### GraphQL subscriptions: Backend
GitLab supports [GraphQL](https://graphql.org) for clients to request structured data from the server
using GraphQL queries. Refer to the [GitLab GraphQL overview](../api/graphql/index.md) to learn about why we adopted GraphQL.
GraphQL support in the GitLab backend is provided by the [`graphql-ruby`](https://graphql-ruby.org) gem.
Ordinarily, GraphQL queries are client-initiated HTTP POST requests that follow the standard request-response cycle.
For real-time functionality, we use GraphQL subscriptions instead, which are an implementation of the publish/subscribe pattern.
In this approach the client first sends a subscription request to the `GraphqlChannel` with the:
- Name of the subscription `field` (the event name).
- GraphQL query to run when this event triggers.
This information is used by the server to create a `topic` that represents this event stream. The topic is a unique name
derived from the subscription arguments and event name and is used to identify all subscribers
that need to be informed if the event triggers. More than one client can subscribe to the
same topic. For example, `issuableAssigneesUpdated:issuableId:<hashed_id>` might serve as the topic
that clients subscribe to if they wish to be updated whenever the assignees for the issue with the
given ID change.
The backend is responsible for triggering a subscription, typically in response to a domain
event such as "issue added to epic" or "user assigned to issue". At GitLab, this could be a service object
or an ActiveRecord model object.
A trigger is executed by calling into [`GitlabSchema.subscriptions.trigger`](https://gitlab.com/gitlab-org/gitlab/-/blob/5e3c334116178eec5f50fc5fee2ec0b3841a2504/app/graphql/graphql_triggers.rb) with the respective event name and arguments,
from which `graphql-ruby` derives the topic. It then finds all subscribers for this topic, executes the query for
each subscriber, and pushes the result back to all topic subscribers.
Because we use Action Cable as the underlying transport for GraphQL subscriptions, topics are implemented
as Action Cable broadcastings, which as mentioned above represent Redis PubSub channels.
This means that for each subscriber, two PubSub channels are used:
- One `graphql-event:<namespace>:<topic>` channel per each topic. This channel is used to track which client is subscribed
to which event and is shared among all potential clients. The use of a `namespace` is optional and it can be blank.
- One `graphql-subscription:<subscription-id>` channel per each client. This channel is used to transmit the query result
back to the respective client and hence cannot be shared between different clients.
The next section describes how the GitLab frontend uses GraphQL subscriptions to implement real-time updates.
### GraphQL subscriptions: Frontend
Because the GitLab frontend executes JavaScript, not Ruby, we need a different GraphQL implementation
to send GraphQL queries, mutations, and subscriptions from the client to the server.
We use [Apollo](https://www.apollographql.com) to do this.
Apollo is a comprehensive implementation of GraphQL in JavaScript and is split into `apollo-server` and `apollo-client`
as well as additional utility modules. Because we run a Ruby backend, we use `apollo-client` instead of `apollo-server`.
It simplifies:
- Networking, connection management and request routing.
- Client-side state management and response caching.
- Integrating GraphQL with view components using a bridge module.
NOTE:
When reading the Apollo Client documentation, it assumes that React.js is used for view rendering. We do not use React.js
at GitLab. We use Vue.js, which integrates with Apollo using the [Vue.js adapter](https://apollo.vuejs.org/).
Apollo provides functions and hooks with which you define how:
- Views send queries, mutations or subscriptions.
- Responses should be dealt with.
- Response data is cached.
The entry point is `ApolloClient`, which is a GraphQL client object that:
- Is shared between all view components on a single page.
- All view components use internally to communicate with the server.
To decide how different types of requests should be routed, Apollo uses the `ApolloLink` abstraction. Specifically,
it splits real-time server subscriptions from other GraphQL requests using the `ActionCableLink`. This:
- Establishes the WebSocket connection to Action Cable.
- Maps server pushes to an `Observable` event stream in the client that views can subscribe to in order to update themselves.
For more information about Apollo and Vue.js, see the [GitLab GraphQL development guide](fe_guide/graphql.md).