Skip to content

Commit

Permalink
api: Connection recovery for ably-js with a callback
Browse files Browse the repository at this point in the history
  • Loading branch information
mattheworiordan committed May 7, 2016
1 parent 6280d70 commit e1daaf6
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 5 deletions.
30 changes: 26 additions & 4 deletions content/realtime/connection.textile
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,33 @@ There are two modes of connection state recovery:

* @resume@: this is transparent recovery of a live client instance across disconnections. Upon disconnection, the library will automatically re-attempt connection and, once the connection is re-established, any missed messages will be sent to the client. The developer does not need to do anything to trigger this behaviour; all client channel event listeners remain attached and are called when the backlog of messages is received.

* @recover@: this addresses the case in which a new client library instance wishes to connect and recover the state of an earlier connection. This occurs typically in a browser environment when the page has been refreshed and therefore the client instance is disposed and no client state is retained. In this case any message listeners associated with channels will no longer exist so it is not possible for the library simply to send the message backlog on reconnection; instead the client must re-subscribe to each channel it is interested in, and its message listener(s) will be called with any message backlog for that channel. A client requests recovery of connection state by including a recovery string in the "client options":/realtime/usage#client-options when instancing the Realtime library. See "connection state recover options":#connection-state-recover-options for more info.
* @recover@: this addresses the case in which a new client library instance wishes to connect and recover the state of an earlier connection. This occurs typically in a browser environment when the page has been refreshed and therefore the client instance is disposed and no client state is retained. In this case any message listeners associated with channels will no longer exist so it is not possible for the library simply to send the message backlog on reconnection; instead the client must re-subscribe to each channel it is interested in within 15 seconds, and its message listener(s) will be called with any message backlog for that channel. If the previously attached channels are not re-attached within 15 seconds of a connection being recovered, the channels will automatically be detached by Ably. A client requests recovery of connection state by including a recovery string in the "client options":/realtime/usage#client-options when instancing the Realtime library. See "connection state recover options":#connection-state-recover-options for more info.

In either case, when a connection is resumed or recovered, the message backlog held on the server will be pushed to the client. However, any new messages published will be sent as they become available or messages could be indefinitely deferred on very heavily loaded connections. Therefore the system does not guarantee that messages received after reconnection are delivered in the same order that would have occurred if the connection had not been dropped. In the @recover@ case, in particular, the order of the message delivery depends on the timing of the re-attachment of each channel.

h4(#connection-state-recover-options). Connection state recover options

In @recover@ mode it is necessary to request recovery mode in the "client options":/realtime/usage#client-options when instancing the library. Recovery requires that the library knows the most previous connection's <span lang="default">"@recoveryKey@":#recovery-key</span><span lang="ruby">"@recovery_key@":#recovery-key</span> value, which includes both the private unique "@Connection#key@":#key and the last message serial received on that connection. As the recovery key is never shared with any other clients, it allows Ably to safely resend message backlogs to the original client.
In @recover@ mode it is necessary to request recovery mode in the "client options":/realtime/usage#client-options when instancing the library. Recovery requires that the library knows the previous connection's <span lang="default">"@recoveryKey@":#recovery-key</span><span lang="ruby">"@recovery_key@":#recovery-key</span> value (which includes both the private unique "@Connection#key@":#key and the last message serial received on that connection). As the recovery key is never shared with any other clients, it allows Ably to safely resend message backlogs to the original client.

blang[javascript].
In the browser environment a @window close@ event causes those parameters to be saved in a cookie; a client can then request recovery simply by including @recover: true@ in the initialization options.
In the browser environment, if a callback is provided in the @recover@ option, when @window beforeunload@ event fires, the connection details, including the "@recoveryKey@":#recovery-key, are stored in the "browser's sessionStorage":https://developer.mozilla.org/en/docs/Web/API/Window/sessionStorage. The provided @recover@ callback is then invoked whenever the connection state can be recovered and just before a connection is established, passing in the "@LastConnectionDetails@":#last-connection-details. The callback is then responsible for confirming whether the connection state should be recovered or not. For example, it is common to recover connection state when the page is reloaded but not for different pages the user has navigated to. The callback allows the developer to decide if the connection should be recovered or not at the time the new connection is established by inspecting the "@LastConnectionDetails@":#last-connection-details and evaluating that against any other application state. Below is a straightforward example:

Alternatively, if it is necessary to be explicit about the connection @recoveryKey@ - for example if there are multiple tabs and the cookies would conflict, or if third-party cookies are disabled - the connection can be recovered by providing the last value of the connection's @recoveryKey@ value in the "client options":/realtime/usage#client-options @recover@ attribute when instancing the library.
```[jsall]
var ably = new Ably.Realtime({
authUrl: '/obtainToken',
recover: function(lastConnectionDetails, cb) {
if (lastConnectionDetails.url === document.location.href) {
cb(true); /* recover connection as user has reloaded page */
} else {
cb(false); /* do not recover connection as URL has changed */
}
}
});
```

Alternatively, if it is necessary to be explicit about the connection @recoveryKey@ , the connection can be recovered by providing the last value of the connection's @recoveryKey@ value in the "client options":/realtime/usage#client-options @recover@ attribute when instancing the library.

h4. Connection recovery constraints

Connection recovery requires that the new client library instance uses credentials that are compatible with those used for the inherited connection; this requires that the same authentication mode is used, with the same key. If token auth was used, the same token is not required, but the token used must have the same @capability@ and <span lang="default">@clientId@</span><span lang="ruby">@client_id@</span>. This ensures that the client recovering the connection cannot receive a backlog of messages that its new credentials are not entitled to access. Incompatible credentials will result in an unrecoverable connection error.

Expand Down Expand Up @@ -322,6 +337,7 @@ inline-toc.
- ConnectionState#connection-state
- ConnectionStateListener#connection-state-listener
- ConnectionStateChange#connection-state-change
- LastConnectionDetails#last-connection-details

h2(#properties).
default: Connection Properties
Expand Down Expand Up @@ -550,3 +566,9 @@ h3(#connection-state-change).
ruby: ConnectionStateChange

<%= partial 'types/_connection_state_change' %>

h3(#last-connection-details).
javascript: LastConnectionDetails

blang[javascript].
<%= partial 'types/_last_connection_details', indent: 2, skip_first_indent: true %>
7 changes: 7 additions & 0 deletions content/realtime/types.textile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jump_to:
- Connection State Listener
- Connection State Change
- Deferrable
- LastConnnectionDetails#last-connection-details
- Message Listener
- Presence Listener
- Token Params
Expand Down Expand Up @@ -224,6 +225,12 @@ h3(#message-listener).
blang[java].
<%= partial 'types/_message_listener', indent: 2, skip_first_indent: true %>

h3(#last-connection-details).
javascript: LastConnectionDetails

blang[javascript].
<%= partial 'types/_last_connection_details', indent: 2, skip_first_indent: true %>

h3(#presence-listener).
java: io.ably.lib.realtime.Presence.PresenceListener

Expand Down
12 changes: 12 additions & 0 deletions content/types/_last_connection_details.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
A @LastConnectionDetails@ object provides details on the last connection in a browser environment persisted when the @window beforeunload@ fired. This object is provided to the callback specified in the @recover@ attribute of "@ClientOptions@":/realtime/types#client-options. The callback in turn instructs the client library whether the connection should be recovered or not. See "connection state recovery":/realtime/connection/#connection-state-recovery for more information.

h4.
default: Properties

- recoveryKey := An opaque string obtained from the "recoveryKey":/realtime/connection/#recovery-key attribute of the "Connection object":/realtime/connection before the page was unloaded. This property is used by the library to recover the connection<br>__Type: @String@__

- disconnectedAt := the time at which the previous library was abruptly disconnected before the page was unloaded. This is represented as milliseconds since epoch<br>__Type: @Integer@__

- url := the URL of the previous page before the page was unloaded. A common use case for this attribute is to ensure that the previous page URL is the same as the current URL before allowing the connection to be recovered. For example, you may want the connection to be recovered only for page reloads, but not when a user navigates to a different page<br>__Type: @String@__

- clientId := the "@clientId@":/realtime/authentication/#client-id of the "client's Auth object":/realtime/authentication before the page was unloaded. A common use case for this attribute is to ensure that the current logged in user's @clientId@ matches the previous connection's @clientId@ before allowing the connection to be recovered. Ably prohibits changing a @clientId@ for an existing connection, so any mismatch in @clientId@ during a recover will result in the connection moving to the failed state<br>__Type: @String@__
4 changes: 3 additions & 1 deletion content/types/_realtime_client_options.textile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

- <span lang="default">autoConnect</span><span lang="ruby">:auto_connect</span> := _true_ By default as soon as the client library is instanced it will connect to Ably. You can optionally set this to false and explicitly connect to Ably when require using the "@connect@":/realtime/usage/#connect method.<br>__Type: @Boolean@__

- <span lang="default">recover</span><span lang="ruby">:recover</span> := This option allows a connection to inherit the state of a previous connection that may have existed under a different instance of the Realtime library. This might typically be used by clients of the browser library to ensure connection state can be preserved when the user refreshes the page. See "connection state recovery":/realtime/connection/#connection-state-recovery for further information on this option.<br>__Type: @String@__
- <div lang="javascript">recover</div> := This option allows a connection to inherit the state of a previous connection that may have existed under a different instance of the Realtime library. This might typically be used by clients of the browser library to ensure connection state can be preserved when the user refreshes the page. A recovery key string can be explicitly provided, or alternatively if a callback function is provided, the client library will automatically persist the recovery key between page reloads and call the callback when the connection is recoverable. The callback is then responsible for confirming whether the connection should be recovered or not. See "connection state recovery":/realtime/connection/#connection-state-recovery for further information.<br>__Type: @String@, @Callable@__

- <div lang="java,ruby,nodejs,objc,swift"><span lang="default">recover</span><span lang="ruby">:recover</span></div> := This option allows a connection to inherit the state of a previous connection that may have existed under a different instance of the library. This might typically be used by clients of an app to ensure connection state can be preserved following a reload. See "connection state recovery":/realtime/connection/#connection-state-recovery for further information and example code.<br>__Type: @String@__

- <span lang="default">queryTime</span><span lang="ruby">:query_time</span> := _false_ If true, the library will query the Ably servers for the current time instead of relying on a locally-available time of day<br>__Type: @Boolean@__

Expand Down

0 comments on commit e1daaf6

Please sign in to comment.