Connection Management
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 PubNub, it's important to understand how and when a PubNub SDK is creating connections so you can handle any network errors that might occur.
Get Connected
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 (they are present in the logs) 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.
Handle 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 and each message is persisted for no more than 20 minutes. Publishing more than 100 messages results in older messages overflowing the queue and getting discarded.
To guarantee message availability via access to historical messages, we suggest that you use Message Persistence.
Connection Types
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.
Subscribe Connections
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).
Non-Subscribe Connections
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).
Connection Timeout
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 listener in the form of PNTimeoutCategory
.
Timeout Troubleshooting
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.
Timeout Configuration
Depending on your use case, you may want to adjust the default 15-second 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.
Connection timeout
For more information, refer to each SDK's Configuration API docs (connectionTimeout
).
Subscribe
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 (name may vary across SDKs) is sent back to your connection status listener. For more information, refer to each SDK's connection status listener API, for example in Kotlin.
That status event will include all channels which were successfully subscribed in that request.
SDKs
The event payload may vary across SDKs.
{
"category": "PNConnectedCategory",
"operation": "PNSubscribeOperation",
"affectedChannels": ["ch1", "ch2"],
"subscribedChannels": ["ch1", "ch2"],
"affectedChannelGroups": [],
"lastTimetoken": 0,
"currentTimetoken": "15856996387695942"
}
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.
{
"category": "PNConnectedCategory",
"operation": "PNSubscribeOperation",
"affectedChannels": ["ch3", "ch4"],
"subscribedChannels": ["ch1", "ch2", "ch3", "ch4"],
"affectedChannelGroups": [],
"lastTimetoken": "15856996387695942",
"currentTimetoken": "15856996387695942"
}
When you unsubscribe from one of those channels, the status event would not include a category
for that but there is an operation
.
{
"error": false,
"operation": "PNUnsubscribeOperation",
"statusCode": 200,
"affectedChannels": ["ch1", "ch2"],
"affectedChannelGroups": [],
"currentTimetoken": "15856996387695942",
"lastTimetoken": "15856996387695942"
}
You don't need to monitor this event unless you're explicitly looking for validation that the unsubscribe request succeeded.
Connection Issues
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.
Connection Drop
PubNub's client SDKs detect this and a status event is sent to your Status handler.
{"category":"PNNetworkDownCategory"}
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" .
Reconnect
When the connection does finally come back, the browser is able to detect this and a PNNetworkUpCategory
is sent to your Status handler.
{"category":"PNNetworkUpCategory"}
Restore Channels Subscription
For the browser, the JavaScript SDK can be configured to resubscribe to the same channels it was previous subscribed to before the connection issue occurred. This configuration is the restore
property. When restore
is enabled, the JavaScript SDK caches the currently subscribed channels automatically, but it does not do this when restore
is disabled.
If restore
property is set to true
, then the JavaScript SDK will automatically subscribe to the same channels it was before the network went down. However, if this property is 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.
It's important to reiterate that the above is true only for the JavaScript SDK in a browser. For other SDKs on other platforms, this isn't the case and isn't something that PubNub can directly improve upon. For other SDKs, if the attempt to connect fails or if there is a timeout, the SDK knows that there is a connection issue and can go into reconnection policy mode.
SDK Connection Lifecycle
PubNub SDKs use standardized workflows for the subscribe and presence lifecycles and implement configurable auto-retry policies that dictate how the SDK behaves when there are network issues. This way, PubNub ensures the stability and predictability of connections across different programming languages.
SDK Statuses
During the subscribe workflow, there are a few statuses the SDK may emit.
Status | Description |
---|---|
Connected | The workflow is running, and messages/events are being received. |
Disconnected | The workflow is not running, and messages/events are not being received. This status can only be emitted when the connection to the PubNub network was established (the Connected status was emitted). If you intentionally disconnect using the disconnect() method, you must reconnect manually using the reconnect() method. Calling subscribe() after disconnecting won't reestablish the connection to the PubNub network. |
Connection error | The workflow is not running because the connection retries have reached the maximum number of attempts trying to initially connect to the PubNub network. No messages/events have been received as the connection wasn't established. |
Disconnected unexpectedly | The workflow is not running because, after receiving messages/events, the client disconnected and connection retries have reached the maximum number of attempts trying to reestablish the connection to the PubNub network. |
Reconnection policy
You can configure the automatic reconnection behavior of the SDK when you initialize the PubNub object. There are several configuration options (policies) available:
- 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
Reconnecting and usage
The retries don't count as transactions in your PubNub usage because none of these actually reach the PubNub network to be counted until one succeeds. At this point, it stops retrying.
Default reconnection policy
By default, PubNub SDKs are configured to exponentially retry subscribe operations only. The subscribe connection is retried up to 6 times with the delay between failed attempts ranging from 2 to 150 seconds.
SDK reconnection policy parity
Certain SDKs do not retry subscribe operations by default. For more information on which operations are retried, refer to your SDK’s configuration documentation, for example, JavaScript, Kotlin, or Python.
Reconnection policy details
The maximum number of reconnect attempts is 10
for linear and 6
for exponential. The minimum retry interval for all policies is 2 seconds. A random break from 0,001 to 0,999 seconds is added to each retry attempt.
Linear
The linear reconnection policy has several configurable parameters. The table below uses Rust as an example, but note that the syntax and data types may differ across SDKs.
Parameter | Type | Description |
---|---|---|
delay | u64 | The delay in seconds between failed retry attempts. |
max_retry | u8 | Number of times a request can be retried. |
excluded | Option<Vec<Endpoint>> | Endpoints that won't be retried. Refer to Exclude endpoints from auto retry for more information. |
Exponential
The exponential retry backoff starts at i = 0
and increases exponentially (min_delay*2^i
where i
is the iteration) with each attempt until it reaches the value of max retry attempts. The interval between the reconnection attempts never exceeds the value of the max_delay
parameter. The exponential reconnection policy also has several configurable parameters:
Parameter | Type | Description |
---|---|---|
min_delay | u64 | Minimum delay in seconds between failed retry attempts. |
max_delay | u64 | Maximum delay in seconds between failed retry attempts. |
max_retry | u8 | Number of times a request can be retried. |
excluded | Option<Vec<Endpoint>> | Endpoints that won't be retried. Refer to Exclude endpoints from auto retry for more information. |
Exclude endpoints from auto retry
Our SDKs also allow you to optionally specify one or more endpoints (features) for which the retry policy won't be applied. Excluding an endpoint from the auto-retry logic turns off the automatic retry policy. Refer to each SDK's documentation for more information.
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
Scenario 1
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.
More Information
For more information about unsubscribing and presence events, refer to Channel Subscriptions and Presence Events.
With Unsubscribing
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 Message Persistence 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
end
parameter). 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 sameend
parameter and updatestart
to 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.
Without Unsubscribing
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 Message Persistence API request to fetch all messages sent since the last received message and store these messages / events without triggering code to handle them. Message Persistence 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.
Scenario 2
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 Notifications feature 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.
For more information on sending APNs and FCM notifications, refer to iOS Mobile Push Notifications and Android Mobile Push Notifications.
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.
Scenario 3
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.
- Your app receives messages in real time using a listener.
- On transition to background, your app unsubscribes from all channels.
- On transition to foreground, your app subscribes to all the channels it unsubscribed from on transition to background.