All PubNub SDKs manage the connection for you so you do not have to worry about device or platform specific nuances of managing the connection. But, to better leverage PuNub, it's important to understand how and when a PubNub SDK is creating connections so you can handle any network errors that might occur.
When you initialize a PubNub object, you do not yet have a connection to the PubNub Network. You just have an object that allows you to invoke PubNub APIs: Publish, Subscribe, and more. It's when you invoke the first API that the connection is made to the PubNub Network to make a request for information or to execute some action. The PubNub Network handles that request and responds appropriately. That response could be that the request was handled successfully and may return some data.
Successful requests will receive a 200 status code as part of the response while requests that result in an error will pass back an appropriate error status code: 400, 404, 413, 414, 500 or other error code. These codes are called HTTP response codes. It's most likely that you're already familiar with these status codes but if you're not it's worth taking some time to do some self study, however you'll not need to do so before you get started with using a PubNub SDK.
The PubNub SDKs will go a long way to shield you from dealing with these codes directly and instead, a status event is triggered in the Status handler of your listener. Knowing how to handle these status events is what you'll need to understand to recover gracefully from any errors.
Handling Network Interruptions
PubNub's automatic reconnection process is designed to handle brief network interruptions like driving through a tunnel, switching from WiFi to cellular, etc. Autoreconnect is able to deliver published messages that were missed during a dropped network connection.
The default message queue size is 100 messages. Consequently, publishing more than 100 messages results in older messages overflowing the queue and getting discarded. The queue is garbage-collected in 5+ minute cycles, so you must not use it for long-term catchup purposes.
To guarantee message availability via access to historical messages, we suggest that you use Storage.
Before we go any further, it's important to distinguish between two types of connections: subscribe and non-subscribe. As the name implies, one type of connection is for the Subscribe API only and the other connection type is for all other APIs: Publish, Here Now, History and more.
A subscribe request creates a long-lived connection. The PubNub SDK makes an HTTP request to the PubNub Network which includes a list of channels to receive messages. When any client sends a message to one of those channels, PubNub responds to that subscribe request with the message content and a
200 status (success). The PubNub SDK will continue to issue new subscribe requests with each successful response to the previous subscribe request.
If no messages are sent on any of those channels after 280 seconds (the subscribe long poll expiration), the PubNub Network responds with no messages and a
200 status. Just like the message sent/received scenario above, the PubNub SDK submits a subsequent subscribe request to continue to listen for messages on those channels.
This subscribe request/response cycle uses the same connection for the entirety of that client's session (the life of the client's PubNub instance).
A non-subscribe connection is short-lived. These connections will be an HTTP connection that hits the PubNub Network to request data with which the PubNub Network will typically respond within milliseconds (depending on the data being requested).
Every API (except Subscribe) has a connection timeout of
15 seconds (may vary per SDK). If there is no response from the PubNub Network after the configured timeout duration has elapsed, the PubNub SDK will abort the connection attempt and report a
timeout error as a status event in the Status handler in the form of
The challenge of troubleshooting a connection timeout is that it's not always obvious how to identify the source of the delay, whether it was your app, your server or client device, your network, DNS, ISP or the PubNub Network.
PubNub provides logs to assist in identifying the root cause for your timeout issues. However, if the request never reaches the PubNub Network, it's much more difficult to troubleshoot.
Implementing logging processes on all points is a great way to troubleshoot. There are also tools like Catchpoint that can assist in troubleshooting.
Depending on your use case, you may want to adjust the default 15 seconds timeout. For example, if you're publishing stock prices at a rate of one price per stock every 250ms, then it may not make sense to wait 15 seconds to find out if that publish request failed. In fact, you might not care if any single publish fails because it's no longer valid 250 ms later (if multiple publishes fail in a short period of time there may be other issues). So you might set the timeout for that request to be much shorter.
The first time you invoke the Subscribe API after initializing the PubNub object, a TCP socket is created on which your subscribe HTTP request to the PubNub Network will be connected. If the subscribe is successful, a
PNConnectedCategory status event is sent back to your Status handler in your listener object. That status event will include all channels which were successfully subscribed in that request.
"affectedChannels": ["ch1", "ch2"],
"subscribedChannels": ["ch1", "ch2"],
If you were to make another subscribe request to new channels, the status event would only include those new channels, however your client is still subscribed to the previous channels.
"affectedChannels": ["ch3", "ch4"],
"subscribedChannels": ["ch1", "ch2", "ch3", "ch4"],
In the preceding sample,
affectedChannels are the newly subscribed channels, and
subscribedChannels includes all the currently subscribed channels.
When you unsubscribe from one of those channels, the status event would not include a
category for that but there is an
"affectedChannels": ["ch1", "ch2"],
However, you probably won't need to monitor this event unless you're looking for validation that the unsubscribe request absolutely did succeed.
Network connection errors are bound to happen, it's important that your application covers the edge cases. Let's walk through some common connection issues.
PubNub's client SDKs are able to detect this and a status event is sent to your Status handler.
At this point, your app should notify the user about the connectivity issues. Note that, your app is unable to execute any more PubNub operations (or other network calls).
Simulating a Network Disconnection
You can simulate a network connection drop error using your browser's console. There is an option to go from "Online" to "Offline".
When the connection does finally come back, the browser is able to detect this and a
PNNetworkUpCategory is sent to your Status handler.
Restore Channels Subscription
restore property. When
restore is disabled.
restore property is set to
false, you'll need to subscribe to those channels manually when the
PNNetworkUpCategory event occurs. You'll also need to keep track of those channels in the client's local cache.
The Reconnection Policy is a configuration that you can set when you initialize the PubNub object. There are three policy options:
- None: default
- Linear: retry connection at set intervals for a set number of attempts
- Exponential: retry connection at exponentially longer intervals for a set number of attempts
The default reconnect attempt setting is infinite. You can limit the number of retries by setting this value: for example, in Java:
setMaximumReconnectionRetries(100). The linear retry interval is 3 seconds and isn't configurable. The exponential retry backoff starts at 1 second and increases exponentially (
2^i - 1) with each attempt: 1, 3, 7, 15, 31 and then it resets to 1 and repeats that cycle until it hits the retry limit if one is set. These retries do not count as transactions in your PubNub usage because none of these actually reach the PubNub Network to be counted until one succeeds, at which point, it stops retrying.
Mobile App Connection Management
Mobile applications can operate while being actively used on screen and while running in the background. Read on to get to know the tips and best practices for managing connections on mobile devices to ensure that you receive all the messages you're interested in reading.
Mobile App Connection Use Cases
Consider the following scenarios:
- Scenario 1: your app runs in the background (offscreen) then it goes on screen and you want to catch up on all messages sent while the app was offscreen
- Scenario 2: your app runs in the background (offscreen), the device loses connectivity and can't continue to receive messages over Pub/Sub and you want to notify the user that they have unread messages when the device goes back online
- Scenario 3: your gaming app runs on screen, goes offline for a short time and reconnects, and you want to display the latest messages without showing the messages the user missed when the app was offline
In this use-case, you want to catch up on all messages that were sent while your app was running in the background.
To handle this situation, you have to first decide whether your app can unsubscribe from channels/channel groups (and, as a consequence send a
leave event) when the app transitions to the background. Of course, if you'd rather your app not unsubscribe then catching up on messages is still possible, yet more complicated to implement.
If your app can unsubscribe as it transitions to the background, the overall flow of message catch-up might look as follows:
- Your app keeps track of the last received message timetoken using a listener.
- On transition to background, your app unsubscribes from all channels.
- On transition to foreground, your app receives and caches new messages, but doesn't process them. At the same time, your app performs a History API request to fetch all messages sent since the last received message (increment the timetoken your app saved in the first step by 1 and use that as the
endparameter). Note that you might need to paginate through the results when the number of missed messages may be high. To get the subsequent page, use the same
endparameter and update
startto be the earliest (smallest) timetoken received from the previous page. Continue to do that until you get 0 messages.
- Send a subscribe call and use the latest (highest) timetoken received in the previous step to start subscribing to the channels/channel groups again.
If your app can't unsubscribe on as it transitions to the background, the overall flow of message catch-up might look as follows:
- Your app keeps track of the last received message timetoken using a listener.
- On transition to background, your app does nothing with regards to channels.
- On transition to foreground, your app performs a History API request to fetch all messages sent since the last received message and store these messages / events without triggering code to handle them. The message storage should consider different channels.
- Continue paginating though history until all messages from all channels have been stored.
- When your app has stored all messages/events, handle them according to your business logic.
In this use-case, you want to send the user a push notification that they have unread messages sent to them while the app was offline in the background.
To handle this situation, you have to register to use a push notification service provider like FCM or APNs, enable Mobile Push on the Admin Portal, and prepare your message's payload accordingly.
When the Mobile Push Gateway is enabled, you may associate unique mobile device tokens to PubNub channel names. Once this association is made, when a message is published to a channel, all associated devices will receive that message via their associated FCM or APNs service.
It's a common misconception about PubNub that the PubNub service is aware of whether the app is in the foreground or background and sends message using the appropriate delivery path. This is incorrect.
How a message is delivered depends on how the user sends it. If there is no push payload in the published message, then the server won’t send out a push notification. The server always sends data published by the user in real time - it's the data that might include the push notification payload and trigger a push notification.
In this use-case, you want to display the latest messages without showing the messages the user missed when the app was offline. This is a common scenario in gaming, where you're only interested in the latest messages/events.