Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Subscriptions and Data Over Time  ›  Lesson

Event-Based Subscriptions

Event Based Subscriptions 14 minOn the server a subscription listens to an event stream: code such as a mutation publishes an event, the subscription filters events by its arguments, runs the client's selection set against each remaining payload and pushes the result.

Event-Based Subscriptions

You now know what a client sees: a stream of reviewAdded results. But where do those results come from? Nothing in the database "sends" anything. On the server, subscriptions are wired to events: something announces that a review was added, and every interested subscriber gets a result.

The rule

Publish the event, filter by arguments, run the selection, push.

Most GraphQL setups use a small publish/subscribe (pub/sub) helper. The mutation that adds a review publishes an event; the subscription field listens for it:

const resolvers = {
  Mutation: {
    addReview: async (_, { input }, { db, pubsub }) => {
      const review = await db.insertReview(input);
      pubsub.publish("REVIEW_ADDED", review);
      return review;
    },
  },
  Subscription: {
    reviewAdded: {
      subscribe: (_, { bookId }, { pubsub }) =>
        onlyWhere(pubsub.subscribe("REVIEW_ADDED"),
                  (review) => review.bookId === bookId),
      resolve: (review) => review,
    },
  },
};

Library names differ (onlyWhere here stands for whatever filter helper yours offers), but the four steps are always the same:

  1. Publish: some code, usually a mutation resolver, announces an event with a payload, here the new review.
  2. Filter: each subscription's subscribe function turns the event stream into only the events it cares about, using the subscription's arguments (bookId).
  3. Run the selection: for each event that passes, the server executes the client's selection set with the payload as the root value. Nested fields such as book { title } run their normal resolvers, once per event.
  4. Push: the finished result goes down that client's open connection.

The event is the trigger, not the answer. A payload can be small (just an ID) as long as resolvers can fetch the rest.

One practical catch: a simple pub/sub lives in one server's memory. If the bookshop runs two server instances and the mutation lands on instance A while the subscriber is connected to instance B, B never hears it. Production setups send events through a shared message broker that every instance listens to.

The shortcut

To debug "my subscriber got nothing", walk the four steps in order and find where the event stopped.

Why didn't the review appear?Step 1 of 4
  1. Publish

    Did addReview call publish("REVIEW_ADDED", ...)? Yes, the log shows it.

Drills

Answer fast — trust the rule.

quick drill

In the bookshop, what causes a reviewAdded result to be sent?

quick drill

A client subscribed with bookId: "b1". A review is added to b2. What does this client receive?

quick drill

A subscriber selects rating book { title }. When does the Book.title resolver run?

quick drill

The mutation runs on server instance A; the subscriber is connected to instance B. With in-memory pub/sub, what happens?

Remember

  • Publish the event, filter by arguments, run the selection, push.
  • Debug by walking those four steps until you find where the event stopped.
  • Trap: in-memory pub/sub does not cross server instances.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainPrice alerts

The shop adds priceChanged(bookId: ID!): Book! to Subscription so readers can watch a book's price. Explain how you would wire it on the server: what publishes the event, how a subscriber watching b2 gets only b2's changes, what runs for each event, and what changes when the shop runs several server instances.