jsonnull/electron-trpc

Incorrect data is returned when using multiple clients

Opened this issue · 0 comments

There is a race condition that causes incorrect data to be returned if there are two different clients. I have two different TRPC clients. The first is a regular client.

function App() {
    const [queryClient] = useState(() => new QueryClient());
    const trpcClient = trpc.createClient({
        links: [loggerLink(), ipcLink()],
        transformer: superjson,
    });

    return (
        <trpc.Provider client={trpcClient} queryClient={queryClient}>
            <QueryClientProvider client={queryClient}>
            </QueryClientProvider>
        </trpc.Provider>
    );
}

The second is a proxy client.

export const trpc = createTRPCReact<AppRouter>();

export const trpcProxyClient = createTRPCProxyClient<AppRouter>({
    links: [loggerLink(), ipcLink()],
    transformer: superjson,
});

I can use the regular client in components, doing things like const result = trpc.path.getData.useQuery(). The proxy client is used in TanStack Router route loaders, as it can be awaited.

export const Route = createRootRouteWithContext<RouterContext>()({
    loader: async ({ context }) => {
        const data = await context.trpcProxyClient.path.getData.query();
        return data;
    },
    component: RootComponent,
});

This causes an issue because the two TRPC clients cause there to be two instances of onMessage.

this.#electronTRPC.onMessage((response: TRPCResponseMessage) => {
this.#handleResponse(response);
});

Each electron-trpc client will have a separate request Operation id.

https://github.com/trpc/trpc/blob/48de686d22ccbefe1cf97eaa7f205dabe7302d2a/packages/client/src/internals/TRPCUntypedClient.ts#L79-L88

Thus, it is possible for the wrong data to be returned in some circumstances. Consider the following:

  1. trpcClient (client 1) is created. It's requestId = 0. An onMessage handler is added.
  2. trpcProxyClient (client 2) is created. It's requestId = 0. An onMessage handler is added.
  3. trpcClient fetches data using requestId = 1.
  4. trpcProxyClient fetches data using requestId = 1.
  5. trpcClient's request completes. Both trpcClient and trpcProxyClient have their onMessage callback trigger with id = 1.
  6. trpcClient fullfils the request with the correct data.
  7. trpcProxyClient's onMessage was called with id = 1, and so it returns incorrect data back to the caller.
  8. trpcProxyClient's request finishes, but #handleResponse has already been run on incorrect data. The correct response is discarded.