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

restartWebsockets does not properly re-open the WebSocket connection #367

Open
jake-leland opened this issue Jun 23, 2020 · 4 comments
Open

Comments

@jake-leland
Copy link

The graphql-client function restartWebsockets is called during the onLogin and onLogout functions provided by the vue-apollo.js template in order to update the authentication header of the WebSocket connection.

// Manually call this when user log in
export async function onLogin (apolloClient, token) {
if (typeof localStorage !== 'undefined' && token) {
localStorage.setItem(AUTH_TOKEN, token)
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
}
}
// Manually call this when user log out
export async function onLogout (apolloClient) {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(AUTH_TOKEN)
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
}
}

restartWebsockets force-closes the current WebSocket connection, opens a new one, and attempts to push all existing subscriptions to the new connection.

export function restartWebsockets (wsClient) {
// Copy current operations
const operations = Object.assign({}, wsClient.operations)
// Close connection
wsClient.close(true)
// Open a new one
wsClient.connect()
// Push all current operations to the new connection
Object.keys(operations).forEach(id => {
wsClient.sendMessage(
id,
MessageTypes.GQL_START,
operations[id].options,
)
})
}

However, manually sending GQL_START messages serves only to restore the WebSocket messages. The message handlers, which were destroyed by wsClient.close, are never restored. Because of this, the Vue-Apollo smart queries/subscriptions will no longer receive updates. A manual refresh of the page is required to fully restore the subscriptions.

Details in subscriptions-transport-ws:

@heivo
Copy link

heivo commented Oct 5, 2020

@jake-leland I think I have the same problem, did you find a solution or workaround for this?

@aullman
Copy link

aullman commented Apr 22, 2021

@jake-leland @heivo I also have the same issue and would love to know whether you found a workaround?

@aullman
Copy link

aullman commented Apr 22, 2021

I think I have just found a workaround which is just to call subscribe again after the websocket is restarted.

I do this by adding a variable (which is not needed) in my subscribeToMore statement that changes when the websocket restarts. In my case I restart the websocket because I log the user in. So when I login I have a new variable "me" which is my own user.

      subscribeToMore: {
        document: onRoomUpdated,
        variables() {
          // Adding meId as a fake variable to force it to re-subscribe when we login
          return { id: this.roomId, meId: this.me.id }
        },
        ...

So this means that after I login, it fetches the me variable and then when that updates Vue detects the change and subscribes again.

@jake-leland
Copy link
Author

@aullman's approach is the simplest workaround I've found. With this workaround, the restartWebsockets function provided by vue-cli-plugin-apollo isn't needed at all. Plus, it seems like other reactive smart subscription options have the same affect of re-subscribing. For example:

subscribeToMore: {
  ...
  skip() {
    return this.me?.id == null
  },
  ...
}

The only other workaround I had tried was to modify the subscriptions-transport-ws library to not actually delete the operation handler. This allowed for the restartWebsockets function to be used as intended, but was an ugly solution. I prefer @aullman's solution as it doesn't require any library modifications.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants