-
Notifications
You must be signed in to change notification settings - Fork 341
Early websocket closure resulting in websocket connections not being instantiated. #377
Comments
Is that what's fixed by #368? |
I am actually not sure. After troubleshooting the issue, it seems like subscriptions-transport-ws will close the connection after only 1200 ms if it hasn't received a response from the server (it uses Backoff, with a hard coded start of 1000ms and a hard coded factor of 1.2).
|
As a temporary fix to this issue, I run the following after the client's instantiation: This is the line where things go awry: subscriptions-transport-ws/src/client.ts Line 489 in 0da7485
|
I'm also having the same problem in |
@arsanjea Thanks a lot. You saved our lives. That one fixed my issue. |
Remove link for consistency
in the big picture, why does |
Oh, it's really stupid issue. Will it be resolved in any near release? |
Is this the same library used in React Graphql? |
I second that. As a user, I will be interested in two timeouts separately: the connects (especially the initial one, which I might treat specially, because it often means I'll have to tell user that the app is unavailable), and the keep-alive. Currently, not only they're clumped together under one Also notably, TCP protocol does have a built-in retransmission which works as early as during the handshake, so this userspace-code ramping up seems to be reinventing the wheel a bit (I appreciate some apps and network setups might not like the OS defaults, but I don't think a general purpose library like this should take an opinionated approach that all users want this). Please remove this ramping up, or at least make the default to not do it. |
@arsanjea But the |
Oh, guess you may not be using TypeScript? But even if I apply the workaround by casting to |
i fixed this by passing |
Same thing happening for me. Establishing the connection to my server seems to take a little bit longer than 1 second. But as this "min" value is hardcoded it makes it worse because it tries and closes it many times. |
maxConnectTimeGenerator is private, so I'm unable to call client.maxConnectTimeGenerator.setMin(3000), how did you work around that? |
@analytically |
On my side this problem occur only on Chrome, when react extension is enabled. If I disable react extension / restart chrome this problem disappear. |
@CyrilSiman That has worked for me also. I wonder if it is due to a recent update to the React Extension as this problem only arose in the past week or so for me |
That @arsanjea workaround worked for me too, what about the roadmap to fix this issue? |
I'm coming from vertx-web/graphql subscriptions and having the same problem. For a temp fix I modified: node_modules/subscriptions-transport-ws/dist/client.js by changing
to
|
Disabling react dev tools (and relaunching chrome) also fixed this issue for me |
Any idea why react-dev tools is causing this issue? I was able to verify that turning the extension off fixed the issue for me as well. I have a hard time believing that the extension is blocking the browser for 2,000+ms. Sometimes the client has to reconnect 4-5 times for the connection to finally work. ( |
OK, I have some information on what is driving this issue and it has something to do with the way async operations are run in JS. The problem is this:
A correct solution would be to start the private connect() {
// ASYNC (native) operation: only starts on yield
this.client = new this.wsImpl(this.url, this.wsProtocols);
// SYNC operation: starts now
this.checkMaxConnectTimeout();
this.client.onopen = async () => {
// ASYNC CHECK (even more time can pass)
if (this.status === this.wsImpl.OPEN) { Should be changed to: // ===> ASYNC CONNECT HERE <===
private async connect() {
// ASYNC (native) operation: only starts on yield
this.client = new this.wsImpl(this.url, this.wsProtocols);
// ASYNC also operation: starts when connect is started (possibly after app bootstrap)
this.checkMaxConnectTimeout();
this.client.onopen = async () => {
// ASYNC CHECK (even more time can pass but should be OK)
if (this.status === this.wsImpl.OPEN) { So whatever the solution, this connect timeout (which I don't really know why it exists) should not mesure application boot time but connection delay (the init message)... |
The "ASYNC" idea does not work with a 1s timeout. // Patching like this works fine for me.:
SubscriptionClient.prototype.createMaxConnectTimeGenerator = function() {
return {
duration() {
return WS_TIMEOUT // mine is at 60000
},
reset() {
// noop
},
}
} |
Thanks for your answer @arsanjea, it helped a lot! One little trick is that it would only work if you have the lazy flag on since otherwise, it will try to connect within the constructor even before putting the workaround in place. I guess the other solutions posted that rely on prototype would not have this issue, but I end up going for this one that I found encapsulate the workaround a little bit more.
|
i am having this exact issue, and for about a week i thought it was my dotnet core proxy that i am writing. i've been beating myself up and scratching my head over it for days and days. thank you @dumorango for a, what i would consider, more proper solution to gain access to the member functions that are attached to the timer. this fixes the connection issue totally to my custom proxy with our SPA, but the playground still doesn't work with the proxy. im ok with that honestly. its a shame that this still hasn't been fixed. very disappointing, but i think i know why. the apollo client with the websocket transport works with graphql-dotnet-server and the apollo servers, but it will not work with certain server implementations apparently, such as my custom proxy and whatever else people are using. which brings me to my question, what are they doing differently than i am? i've been reading and reading over the grapql-dotnet websocket transport middleware, and just cant seem to pinpoint what would cause that to work with apollo client, but not my server. i would be 100000% ok with this not being fixed on the client side, even though it should be, if i could figure out how to make my server work with the current apollo client. |
As @arsanjea pointed out this is the solution i will implement as a workaround in my code: link.subscriptionClient.maxConnectTimeGenerator.duration = () => link.subscriptionClient.maxConnectTimeGenerator.max Im still trying to get around my head how this solution would work, and im unable to understand it. If someone could explain me would be nice. Someone else been having this trouble lately? This is a pretty random problem and its really frustrating. Sometimes it does connect just fine, until this error happens and it keeps trying to reconnect indefinitely. |
I had the same temp fix but #675 now provides a solution with the |
The issue seems to be solved with a minTimeout field on the websocket client. feature wise it's exactly the same, just that it doesn't time out so the console is not filled with a ton of errors. |
This is what the docs say about the
hope this helps 🙃️. |
With [email protected], on the client side, the following error prevents the client from logging in"
WebSocket connection to 'wss://url/subscriptions' failed: WebSocket is closed before the connection is established.
The websocket connection is closed by checkMaxConnectTimeout before the timeout value defined in the client options is reached; which results in websocket subscriptions not being instantiated.
I see the timeout is calculated by
this.maxConnectTimeGenerator.duration();
however, this duration is well below the timeout limit passed by the client.The text was updated successfully, but these errors were encountered: