Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full support for websocket reconnection/resubscription #3167

Closed
wants to merge 12 commits into from

Conversation

cgewecke
Copy link
Collaborator

This is #3135, #1966 redux, merged to the root repo so merge conflicts and tests can be managed here. Tests are WIP, opening as draft.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.2%) to 83.815% when pulling 5c5e95d on staging/reconnect-resubscribe into 9dd09db on 1.x.

@nivida nivida added the 1.x 1.0 related issues label Oct 30, 2019
@nivida
Copy link
Contributor

nivida commented Nov 5, 2019

@cgewecke Sorry for commenting on this draft PR. But I would like to ask you what the state is of the mentioned test cases? Is it possible to commit those and I'm gonna finish them?

@cgewecke
Copy link
Collaborator Author

cgewecke commented Nov 5, 2019

@nivida Ah thanks for the reminder - I will get these in..

gabmontes and others added 12 commits November 5, 2019 20:12
When using `.on<event>=fn` to attach listeners, only one listener can be
set at the same time. Since multiple request managers can use the same
provider, the EventTarget API has to be used to ensure all of them
receive the events emitted from the provider.

This is needed on both the `on` and `removeListener` functions.
The method `once` is required to allow the subscription logic to
identify if the provider is able to reconnect/resubscribe and then
attach to the following `connect` event the function to resubscribe.
When the subscription fails on start and when it fails after it was
successfully established, the same logic needs to be executed: remove
subscription, listen for the next `connect` event if available to
actually subscribe again, emit the error and call the callback.

Prior code did that only for established subscriptions so if a
subscription was unable to be set right on start, no resubscription was
ever tried.

The logic was moved to a single method to avoid duplication of code.
In addition reentry is avoided by checking and properly clearing the
`_reconnectIntervalId` variable.
On subscribe, if there is an existing `id`, the subscription listeners
are removed. In the case of a resubscription, the listeners have to be
kept. Therefore, the `id` property -that will change anyway- must be
cleared so the listeners are not removed.

Then, after the subscription object resubscribes, the listeners set by
the subscription user code remain untouched, making the resubscription
transparent to the user code.
When the request manager removes a subscription due to an error, it
tries to send an unsubscribe package, which can also fail if i.e. the
network is down. In such a case, the function must not allow reentry.
Removing the subscription first ensures it will not do so.

In addition, if the subscription was already removed, the callback shall
be called anyway.
When error events are emitted by the provider, all subscriptions shall
receive the event and trigger the unsubscription/resubscription logic.
By wrapping the available WebSocket implementation (native WebSocket
object or `websocket` package) with `websocket-reconnector`, the
provider is given a WebSocket that will automatically reconnect on
errors.

A new option was added to the WebSocket provider to controll whether it
should automatically reconnect or it should behave as usual.
In the case any websocket call takes too long to return and a timeout
was set for the provider to timeout, the provider should try to restart
the connection.

This could happen, for instance, if the client loses connection with the
server, the server closes the connection and later, the connectivity is
up again but since the client did not receive the closing frame *and*
the client does not attempt to send any package to the server, no error
is observed.

`websocket` implementation for Node.js has an option to send keep-alive
frames and detect such scenarios, but the standard browser W3C WebSocket
does not, so it is "vulnerable" to this kind of failure which will
mostly affect web3 subscriptions.
If the provider silently recoonects and emits a new "connect" event, the subscriptions have to be set again over that new connection.
@cgewecke cgewecke force-pushed the staging/reconnect-resubscribe branch from 5c5e95d to d31f7e2 Compare November 6, 2019 06:35
});

// This test failing....
it.only('auto reconnects', function(){
Copy link
Collaborator Author

@cgewecke cgewecke Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nivida This is my attempt to model reconnection working.

  • Open server
  • Attach a subscription handler
  • Fire a tx (which subscrip hears)
  • Close server
  • Re-open server
  • Fire a tx (which subscrip hears)

But the test doesn't reconnect...do you want to take a look?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make sure this works against an actual client, not just mock some assumptions in.

Copy link
Collaborator Author

@cgewecke cgewecke Nov 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe my model of how to do this is wrong...not sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nivida mentioned something in a chat that's important which I'm leaving here for further reference.

The way this test models disconnection doesn't reflect the connectivity issues people typically have online e.g. nodes are not shutting down, killing their sockets and restarting...

@nivida
Copy link
Contributor

nivida commented Nov 8, 2019

Moved this to #3190

@nivida nivida closed this Nov 8, 2019
@nivida nivida deleted the staging/reconnect-resubscribe branch December 12, 2019 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.x 1.0 related issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants