Change request for: /docs/getting-started/quickstart
Page name: Quickstart guide URL: /docs/getting-started/quickstart
Requested change or enhancement:
Hello, I've got some questions that I wasn't able to glean easily from the documentation. I'm wondering if you could add some language to the docs to make some of these things a bit more clear for readers? :)
Request clarification on Connections:
- When are connections active, relative to the application state on your smartphone? (Foreground, Background, Force Quitted, etc...)
- e.g., if the app is still open but moved to the background, does the connection stay active for some time, or is it immediately killed?
- Are there differences between iOS, Android, etc..?
Request clarification on Subscriptions:
- Assuming a Channel is intended to be long-running (over days/weeks):
- Does a Subscription persist across changes in application state and/or connection state?
- Are you meant to subscribe/unsubscribe repeatedly to a long-running channel, based on your application state?
- If a user unsubscribes to a Channel because of application state changes, will that stop them from receiving Push Notifications for that Channel?
- If a Subscription is intended to be created once, and remain extant for the lifetime of the Channel itself (i.e., days/weeks), then what's the recommended way of persisting the Subscription (ARTEventListener) across the application lifecycle?
- Otherwise, if Subscriptions are intended to be reestablished on application start, is it recommended to persist a list of Channels (ARTRealTimeChannel objects) in UserDefaults or equiv, and then resubscribe on application start?
- How important is it to close connections and subscriptions on deinit() of whatever class you're keeping the Ably client in?
Request Clarification on Channels:
- What are the conditions that make a channel active and inactive?
- (e.g., is it determined by the number of open subscriptions?)
- What if there are Inband Objects? How do they affect the Channel active status?
- When does a Channel get deleted or garbage collected? Is that an automatic thing, or something that needs to be managed?
Thanks very much for the clarification :)
Ah, I clearly wasn't doing a good job of reading the documentation. After a bit more reading, I've found some pages which answer parts of my question:
https://ably.com/docs/connect/states https://ably.com/docs/channels/states
But I'm still in the dark on the lifecycle of Subscriptions (with respect to the application lifecycle)
Hi, thanks for the questions. I'll answer as many as I can here, and then we'll figure out where we need to improve the documentation.
Request clarification on Connections:
When are connections active, relative to the application state on your smartphone? (Foreground, Background, Force Quitted, etc...) e.g., if the app is still open but moved to the background, does the connection stay active for some time, or is it immediately killed?
(See https://ably.com/docs/connect/states.)
The high-level summary is that the client library, in general, always attempts to ensure there is a connection. This is true:
- from the moment that
connect()(https://ably.com/docs/api/realtime-sdk/connection#connect) is first called. This happens by default when the library is initialised so you don't have to do this yourself. (There is anautoConnectclient option that you can specify to be false, which would defer the first connection attempt until you callconnect()explicitly.) - until the connection reaches one of the terminal states, which are:
closed, which only happens as a result of callingclose()explicitly. You would do this when you want the library to close the connection and not attempt to reestablish it;- 'failed`, which happens when there has been an error response from the server indicating that connection will never succeed. Examples of this would be if the associated account is blocked, the API key is invalid or has been revoked, etc.
At all other times the library will attempt to ensure there is a connection irrespective of what happens, whether that's temporary disconnect, loss of network, expiry of a renewable access token, etc. There is a retry sequence, and interval between retries depends on whether it is in the disconnected or suspended state, as defined in the referenced doc.
So in a mobile app, the library will still attempt to establish a connection when in the background. So now there are two further questions:
- is that what you want? If it is, then you don't have to do anything. If you want it to not be connected in the background, then you should call
close()in the relevant application lifecycle event, and callconnect()when you want it reestablished. (If you want to explicitly kick it into reattempting connection at any time you can callconnect(), even if it was already in a retry sequence.) - will the phone OS let it be connected? Both iOS and Android are increasingly aggressive at closing down network activity from apps in the background, and the Ably library does not do anything to prevent it. There are various approaches people take to dealing with that (eg foreground services on Android, or playing sounds in the background) but ultimately it's out of our control and you have to do what you can.
Are there differences between iOS, Android, etc..?
There's no difference in what the Ably client does - ie we don't do anything proactive in response to lifecycle events - but the approaches to dealing with that in the app are different between platforms.
Request clarification on Subscriptions:
Assuming a Channel is intended to be long-running (over days/weeks): Does a Subscription persist across changes in application state and/or connection state?
The existence of a realtime subscription to a given channel is essentially client-side state. After you've initiated the subscription by calling subscribe() (or by triggering the attach() another way), then the client attempts to ensure that it is continuously subscribed. That remains true, for that instance of the library, until you explicitly call detach(), or the channel for some other reason enters the failed state. This means:
- if the connection is
disconnectedand is reestablished, the library will automatically reestablish the attachment to the channel, and it will attempt to do this in a way that is continuous with the previous attachment. As part of the reconnection sequence, the client indicates to the server what the last message received on that channel was, and the server attempts to send all messages since that point. If the server is unable to reestablish the attachment with continuity, then this is indicated in anupdatechannel state event (https://ably.com/docs/channels/states#non-fatal-errors). - if the connection enters the
suspendedstate this signifies that there was an extended period of disconnection, and the library knows that it will no longer be able to reconnect and reattach with continuity. It will still reconnect and reattach, but the channel state change event will indicate (by having theresumedflag to befalse) that it was not continuous; - so if the connection drops because the app was backgrounded, and it later becomes reconnected, then the channel attachment will be reestablished;
- there are circumstances where the channel will enter the
failedstate which is terminal, and the library then knows that there is no point trying to reestablish the channel attachment. This would typically be a result of the client's credentials no longer having permission to access that channel; - there are circumstances where the server will itself initiate the detach of the channel - this would be in the case of some server problem that prevents the channel from working for some reason. In this case the library will still attempt to reattach.
Are you meant to subscribe/unsubscribe repeatedly to a long-running channel, based on your application state?
If you're happy with the default behaviour, then don't change it :) Attach when you want to get messages, and detach when you don't. It's valid to have an subscription exist for extended periods, and the library will ensure it is attached whenever possible.
If a user unsubscribes to a Channel because of application state changes, will that stop them from receiving Push Notifications for that Channel?
No, a push subscription is durable on the server and outlives any change to subscription state, channel state, etc.
If a Subscription is intended to be created once, and remain extant for the lifetime of the Channel itself (i.e., days/weeks), then what's the recommended way of persisting the Subscription (ARTEventListener) across the application lifecycle?
Outside of the lifetime of a library instance, in typical usage there is no client-side durability of client credentials or any other client state. Typically, when re-launching an app (eg after having been terminated in the background) then you would reestablish some application state by authenticating to your backend and, based on that state, the client would know which subscriptions to recreate.
The one exception to this is that the library supports a recover client option (for the browser, see https://ably.com/docs/sdk/js/v1.2/promises/interfaces/Types.ClientOptions.html#recover) that provides a way to reestablish subscriptions with continuity when the library is reinitialised. This does not by itself provide client-side durability, but it provides a way for the library to reestablish some prior state on initialisation, if you persist a "recoverKey" at the time the library exits. This is most often used for continuity across browser page refreshes and is not typically used for recovering when re-launching mobile apps, because those are more usually extended periods of downtime and resuming with continuity isn't relevant.
Otherwise, if Subscriptions are intended to be reestablished on application start, is it recommended to persist a list of Channels (ARTRealTimeChannel objects) in UserDefaults or equiv, and then resubscribe on application start?
Yes, although you would first decide how to manage re-obtaining credentials on application start, and that might involve some re-identification with the backend, etc. If it's an app that multiple users might sign in to then you might need to manage any client-side state on a per-user basis, etc.
How important is it to close connections and subscriptions on deinit() of whatever class you're keeping the Ably client in?
Closing a connection and all associated attachments will happen automatically when the library is close()d. It's preferable to do that explicitly, so that all actions that happen as a result of detaching will happen immediately (leaving presence, for example). However, if you don't explicitly close(), the server will close down any server-side state associated with that individual connection after 15s, and it will enable that connection to resume with continuity for up to 2 minutes.
You don't have to individually close down subscriptions when closing a connection.
Request Clarification on Channels:
What are the conditions that make a channel active and inactive? (e.g., is it determined by the number of open subscriptions?)
A channel will be active if either there is a publisher interacting with the channel, or there is a subscriber. Once there is neither any publisher or subscriber, the channel will become inactive after a short period (typically 30s). In this context, publishers include any REST publish operation or a publish over a realtime connection. This means that a REST publish on a previously-inactive channel will cause it to activate, and be active for ~30s, and then deactivate.
What if there are Inband Objects? How do they affect the Channel active status?
LiveObjects are durable independently of channel activity. So if you activate a channel, publish some Operations (and thereby create Object state), then that state will be persisted, and will continue to exist once you've left the channel and it has become inactive.
Inband Objects are simply a way to subscribe to Object state on a channel. So if you have an Inband Object, that's another way of saying that you're subscribed (and specifically you're subscribed to changes in Object state) - and the act of subscribing will activate the channel if it wasn't already active.
When does a Channel get deleted or garbage collected? Is that an automatic thing, or something that needs to be managed?
Channel activity is a transient thing only while there are publishers or subscribers. There's no need to garbage collect channels.
Persisted state can exist for a channel, and this survives channel deactivation. Persisted state might be persisted messages, or Object state. In both cases state has a Time To Live (TTL) so it is automatically deleted once that has expired. (Persisted messages are persisted with a TTL at the time they are published. At this time in the Experimental LiveObjects release, Objects are persisted similarly, but the TTL is renewed each time any individual object is modified. In a future release this will change so that Object TTLs will renew each time a channel is activated, even if the state is not modified. This will ensure that any channel that is in periodic use will retain all Object state.)
We imagine that at a future time we will provide a way to have indefinite Object storage, along with observability and APIs to manage that storage, but we don't have a firm roadmap for that right now.
Also note the comments about reachability wrt Object storage lifetime.
I hope this helps. We really appreciate the feedback and are happy to answer any further questions.
Thank you so much for a really comprehensive answer to my questions :)
This is super helpful, and I'm felling much more confident that I understand how it all works now. And the behaviours you've described are exactly what I'm looking for, so I'm very optimistic.
Broadly speaking in my use case, I'm expecting clients to remain disconnected for the majority of the time, so channel persistence behaviours are a key design concern. (Also, in my use case there will likely be a large number of small channels with few subscribers, which might be different to other large-fan-out use cases for other customers.)
So in a mobile app, the library will still attempt to establish a connection when in the background. So now there are two further questions:
is that what you want?
Yes, that's perfect
will the phone OS let it be connected?
I know very little about this currently... I assume that iOS will suspend or terminate the process as it goes into the background, based on their documentation, although there seems to be some capacity for background tasks which might be compatible with Ably's functionality: https://developer.apple.com/documentation/BackgroundTasks. (And I can't speak to Android at all at the moment.)
Perhaps a regularly scheduled background task can reactivate the Ably client, fetch and process history on the list of channels, and then yield back to the OS (to be suspended/terminated again). I assume I'll need to build this for now unless Ably has this functionality built in? (I'll keep working away until I understand this better..)
Otherwise, if Subscriptions are intended to be reestablished on application start, is it recommended to persist a list of Channels (ARTRealTimeChannel objects) in UserDefaults or equiv, and then resubscribe on application start?
Yes, although you would first decide how to manage re-obtaining credentials on application start, and that might involve some re-identification with the backend, etc. If it's an app that multiple users might sign in to then you might need to manage any client-side state on a per-user basis, etc.
Yeah, sweet. This is good.
Outside of the lifetime of a library instance, in typical usage there is no client-side durability of client credentials or any other client state. Typically, when re-launching an app (eg after having been terminated in the background) then you would reestablish some application state by authenticating to your backend and, based on that state, the client would know which subscriptions to recreate.
In both cases state has a Time To Live (TTL) so it is automatically deleted once that has expired.
Great, and I understand this is like 90 days currently? That works great.
LiveObjects are durable independently of channel activity. So if you activate a channel, publish some Operations (and thereby create Object state), then that state will be persisted, and will continue to exist once you've left the channel and it has become inactive.
Awesome, this is perfect for my use case.
Thanks again so much for your response :)
Perhaps a regularly scheduled background task can reactivate the Ably client, fetch and process history on the list of channels, and then yield back to the OS (to be suspended/terminated again). I assume I'll need to build this for now unless Ably has this functionality built in?
Correct, we don't have that built in. I imagine there's quite a bit of folklore around concerning what you can do to have connections remaining for a backgrounded app - for example in the case of iOS: https://developer.apple.com/forums/thread/685525.
In both cases state has a Time To Live (TTL) so it is automatically deleted once that has expired.
Great, and I understand this is like 90 days currently? That works great.
90 days for Objects, but 72 hrs by default for messages. Messages TTL can be increased to 30 days on request.