Guide: Handle discontinuity in Pub/Sub

Open in

When a client experiences a period of disconnection longer than the two-minute recovery window, or when Ably signals a loss of message continuity, your application may have missed messages. This is called a discontinuity. This guide explains how to detect and recover from discontinuities in Pub/Sub applications.

What causes discontinuity

Discontinuity occurs when the Ably SDK cannot guarantee that all messages have been delivered to the client. The most common causes are:

  • Network disconnection lasting longer than two minutes. Ably preserves connection state for up to two minutes. Beyond this window, Ably cannot guarantee message continuity.
  • Server-initiated continuity loss. Operational events such as cluster rebalancing may cause a partial loss of message continuity, even if the client remained connected.
  • Outbound rate limits exceeded. If a connection's outbound message rate exceeds the per-connection limit, messages may be dropped, resulting in a loss of continuity.
  • Client app backgrounded for an extended period. Mobile apps suspended by the operating system may exceed the two-minute recovery window.

For disconnections shorter than two minutes, the SDK automatically resumes the connection and replays missed messages without any action from you.

Detect discontinuity

When continuity is lost on a Pub/Sub channel, the client receives an ATTACHED or UPDATE event with the resumed flag set to false. This flag is part of the ChannelStateChange object.

Register listeners for both attached and update events to detect all discontinuity scenarios:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

channel.on('attached', (stateChange) => {
  if (!stateChange.resumed) {
    // Continuity was lost - messages may have been missed
    recoverMissedMessages(channel);
  }
});

channel.on('update', (stateChange) => {
  if (!stateChange.resumed) {
    // Mid-session continuity loss
    recoverMissedMessages(channel);
  }
});
  • An attached event with resumed set to false occurs when a channel reattaches after the connection was suspended, for example after a disconnection longer than two minutes.
  • An update event with resumed set to false occurs when there is a partial loss of continuity on a channel that remains attached, such as after a partially successful resume.

Recover missed messages

Use channel.history() with untilAttach set to true to retrieve messages up to the point of reattachment. The response is paginated, so you may need to iterate through multiple pages. You are responsible for determining how far back to go, for example by using time bounds or checking message serials against the last message you processed:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

async function recoverMissedMessages(channel, lastSeenSerial) {
  let page = await channel.history({ untilAttach: true });

  while (page) {
    for (const msg of page.items) {
      if (msg.serial <= lastSeenSerial) {
        // Reached messages already processed
        return;
      }
      processMessage(msg);
    }

    page = page.hasNext() ? await page.next() : null;
  }
}

Best practices

  • Set up discontinuity handlers before subscribing to messages or attaching to channels. This ensures you detect any continuity loss that occurs during the initial attachment.
  • Use untilAttach: true with channel.history() for recovery. This is designed to work with the resumed flag detection mechanism.
  • History results may overlap with messages already received via the live subscription. Design your message processing to tolerate duplicates, for example by tracking message IDs or serials.
  • Decide how to present recovered messages to the user. Options include silently inserting them into the message list, showing a "new messages" indicator, or displaying a notification that messages were recovered.