Skip to content

bug: wsLink won't close if there are running subscriptions.  #4133

@gunhaxxor

Description

@gunhaxxor

Provide environment information

System:
   OS: Linux 5.10 Ubuntu 20.04.5 LTS (Focal Fossa)
   CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
   Memory: 6.37 GB / 12.37 GB
   Container: Yes
   Shell: 5.0.17 - /bin/bash
 Binaries:
   Node: 18.12.1 - ~/.nvm/versions/node/v18.12.1/bin/node
   Yarn: 1.22.15 - ~/.yarn/bin/yarn
   npm: 8.19.2 - ~/.nvm/versions/node/v18.12.1/bin/npm
 Browsers:
   Chrome: 109.0.5414.119
 npmPackages:
   @trpc/client: ^10.8.1 => 10.8.1 
   @trpc/react-query: ^10.8.1 => 10.8.1 
   @trpc/server: ^10.8.1 => 10.8.1 
   typescript: ^4.8.3 => 4.9.4 

Describe the bug

Explicitly calling wsClient.close() doesnt close the link if there are running subscriptions.
Calling close should presumably unsubscribe all running subscriptions and close websocket.
As of now the client code must keep track of all running subscriptions and close them one by one in addition to closing the wsClient.

Link to reproduction

https://stackblitz.com/edit/github-6nnmqf?file=src/client.ts&view=editor

To reproduce

import {
  createTRPCProxyClient,
  createWSClient,
  httpLink,
  splitLink,
  wsLink,
} from '@trpc/client';
import AbortController from 'abort-controller';
import fetch from 'node-fetch';
import ws from 'ws';
import type { AppRouter } from './server';

// polyfill fetch & websocket
const globalAny = global as any;
globalAny.AbortController = AbortController;
globalAny.fetch = fetch;
globalAny.WebSocket = ws;

const wsClient = createWSClient({
  url: `ws://localhost:2022`,
});
const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    // call subscriptions through websockets and the rest over http
    splitLink({
      condition(op) {
        return op.type === 'subscription';
      },
      true: wsLink({
        client: wsClient,
      }),
      false: httpLink({
        url: `http://localhost:2022`,
      }),
    }),
  ],
});

async function main() {
  const helloResponse = await trpc.greeting.hello.query({
    name: 'world',
  });

  console.log('helloResponse', helloResponse);

  const createPostRes = await trpc.post.createPost.mutate({
    title: 'hello world',
    text: 'check out https://tRPC.io',
  });
  console.log('createPostResponse', createPostRes);

  let count = 0;
  await new Promise<void>((resolve) => {
    const subscription = trpc.post.randomNumber.subscribe(undefined, {
      onData(data) {
        // ^ note that `data` here is inferred
        console.log('received', data);
        count++;
        if (count > 20) {
          subscription.unsubscribe();
        }
      },
      onError(err) {
        console.error('error', err);
      },
      onStarted(){
        resolve();
      }
    });
  });
  console.log('gonna close wsClient');
  wsClient.close();
}

main();

Additional information

No response

👨‍👧‍👦 Contributing

  • 🙋‍♂️ Yes, I'd be down to file a PR fixing this bug!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions