bun icon indicating copy to clipboard operation
bun copied to clipboard

Bun doesn't support Apollo Server GraphQL subscription

Open HuakunShen opened this issue 1 year ago • 17 comments

What version of Bun is running?

1.0.8+2a405f691e80725fe0b97b93afd3b8cfed13fa5f

What platform is your computer?

Darwin 23.1.0 arm64 arm

What steps can reproduce the bug?

Get this project and run it with nodejs and bun. https://github.com/apollographql/docs-examples/blob/main/apollo-server/v4/subscriptions-graphql-ws/src/index.ts

git clone https://github.com/apollographql/docs-examples.git
cd docs-examples/apollo-server/v4/subscriptions-graphql-ws

NodeJS Version

npm install
npm start

Bun Version

bun install

bun --bun run start  # make sure to use the --bun flag
#  the start script runs bun run compile && node ./dist/index.js

# or run TypeScript directly without compiling to JS
bun src/index.ts

Open http://localhost:4000/graphql

Use subscription query

subscription Subscription {
  numberIncremented
}

What is the expected behavior?

GraphQL subscription should work. When running with NodeJS, it works fine.

I see the number incremented messages keep showing up

image

What do you see instead?

When running with bun, it doesn't connect at all.

image

Additional information

GraphQL mutation and query works fine with bun runtime, probably because they are in nature simply http post request. Not sure why graphql subscription doesn't work. I believe they use WebSocket, which bun should support, but for some reason doesn't work, and no error is shown.

I don't know where to start debugging. I am guessing apollo uses some nodejs API that bun has not implemented.

HuakunShen avatar Nov 05 '23 03:11 HuakunShen

@HuakunShen Do you mind to retry with Bun v1.0.15 (https://bun.sh/blog/bun-v1.0.15#stable-websocket-client)

root-io avatar Dec 04 '23 14:12 root-io

@root-io It still doesn't work after upgrading to v1.0.15

HuakunShen avatar Dec 05 '23 00:12 HuakunShen

I'm also using v1.0.15 and having problems with this

acrogenesis avatar Dec 05 '23 03:12 acrogenesis

Your example is using WebSocketServer from https://github.com/websockets/ws maybe open an issue with them

root-io avatar Dec 05 '23 11:12 root-io

i'm experiencing this exact issue as well. would love to see it fixed. also if anyone thinks of a work around i would love to hear that as well :wink:

ioitiki avatar Dec 06 '23 05:12 ioitiki

I'm using packages ws, graphql-ws, http and express and I can't get my Apollo Subscriptions to work. The client websocket appears to connect, but the server never sends any data over the connection. I'm not sure where the problem is originating.

graphql-ws does ship a Bun integration, but it does not change the fact that there is some kind of Node compatibility issue going on here with Bun.

bnussman avatar Dec 07 '23 02:12 bnussman

Brothers, I have some good news: my GraphQL websockets started to work. I upgraded to the latest canary and things seem to be working! 🎉 I'm not sure which commit resolved this though.

The only issue I'm seeing now is this error flooding my console

64 |                         if (pongWait) {
65 |                             clearTimeout(pongWait);
66 |                             pongWait = null;
67 |                         }
68 |                     });
69 |                     socket.ping();
                         ^
TypeError: socket.ping is not a function. (In 'socket.ping()', 'socket.ping' is undefined)
at /home/banks/Development/beep/node_modules/graphql-ws/lib/use/ws.js:69:21

bnussman avatar Jan 13 '24 02:01 bnussman

@Jarred-Sumner take a look? 👉👈 🥺

Creative-Difficulty avatar Jan 14 '24 18:01 Creative-Difficulty

With bun v1.0.22, I now get response for the first subscription query, but no update after that. Then I got errors in console.

image

Not only socket.ping, but also socket.terminate().

      at /Users/hacker/Documents/Learn/graphql/apollographql/docs-examples/apollo-server/v4/subscriptions-graphql-ws/node_modules/graphql-ws/lib/use/ws.mjs:57:25
61 |                         if (pongWait) {
62 |                             clearTimeout(pongWait);
63 |                             pongWait = null;
64 |                         }
65 |                     });
66 |                     socket.ping();
                         ^
TypeError: socket.ping is not a function. (In 'socket.ping()', 'socket.ping' is undefined)
      at /Users/user/apollographql/docs-examples/apollo-server/v4/subscriptions-graphql-ws/node_modules/graphql-ws/lib/use/ws.mjs:66:21
52 |             ? setInterval(() => {
53 |                 // ping pong on open sockets only
54 |                 if (socket.readyState === socket.OPEN) {
55 |                     // terminate the connection after pong wait has passed because the client is idle
56 |                     pongWait = setTimeout(() => {
57 |                         socket.terminate();
                             ^
TypeError: socket.terminate is not a function. (In 'socket.terminate()', 'socket.terminate' is undefined)
      at /Users/user/apollographql/docs-examples/apollo-server/v4/subscriptions-graphql-ws/node_modules/graphql-ws/lib/use/ws.mjs:57:25

HuakunShen avatar Jan 15 '24 20:01 HuakunShen

Getting the same issue

1 |         pongWait = setTimeout(() => {
22 |           socket.terminate();
23 |         }, keepAlive), socket.once("pong", () => {
24 |           if (pongWait)
25 |             clearTimeout(pongWait), pongWait = null;
26 |         }), socket.ping();
                 ^
TypeError: socket.ping is not a function. (In 'socket.ping()', 'socket.ping' is undefined)
      at /Users/user/Github/server/node_modules/.pnpm/[email protected][email protected]/node_modules/graphql-ws/lib/use/ws.mjs:26:13
17 |     });
18 |     let pongWait = null;
19 |     const pingInterval = keepAlive > 0 && isFinite(keepAlive) ? setInterval(() => {
20 |       if (socket.readyState === socket.OPEN)
21 |         pongWait = setTimeout(() => {
22 |           socket.terminate();
               ^
TypeError: socket.terminate is not a function. (In 'socket.terminate()', 'socket.terminate' is undefined)
      at /Users/user/Github/server/node_modules/.pnpm/[email protected][email protected]/node_modules/graphql-ws/lib/use/ws.mjs:22:11

Akumzy avatar Jan 25 '24 21:01 Akumzy

on v1.0.26

I've been trying to find a hacky solution to this and I think I've got something that will work for now.

wsServer.on('connection', (socket) => {
  // Check if the socket has a ping method
  if (!socket.ping) {
    socket.ping = () => {
      if (socket.readyState === WebSocket.OPEN) {
        // Send a keep-alive message expected by Apollo Client
        // socket.send(JSON.stringify({ type: 'pong' }));
        console.log('Keep-alive message sent');
      }
    };
  }

  if (!socket.terminate) {
    // If not, polyfill it with a custom implementation
    socket.terminate = () => {
      console.log('Terminate method called');
      if (socket.close) {
        socket.close();
      } else {
        console.warn('Socket does not have a close method');
      }
    };
  }

  // const keepAliveInterval = setInterval(() => {
  //   if (socket.readyState !== WebSocket.OPEN) {
  //     clearInterval(keepAliveInterval);
  //   } else {
  //     socket.ping();
  //   }
  // }, 30000);
});

I've left some comments in there to show some of what I've tried. Would love to see what you guys think :D

ioitiki avatar Feb 05 '24 20:02 ioitiki

@Jarred-Sumner

Creative-Difficulty avatar Feb 06 '24 13:02 Creative-Difficulty

I had the same issue and went searching into the graphql-ws library to see what goes wrong. Every time the promise "socket.send" is called in the file /lib/server.mjs file, the promise is executed but never resolves (nor rejects).

By removing all those awaits from those calls, the subscription technically works

It also solves the ping problem, since the answer to a ping is also a socket.send_message

I didn't find a way to override this behavior by not fiddling into the library

I hope this can help

ahirel avatar Feb 28 '24 14:02 ahirel

This issue seems to be related to https://github.com/oven-sh/bun/issues/7346 - at least the root of the problem in both situations point into the same direction

Andy9822 avatar Mar 02 '24 07:03 Andy9822

It seems Bun v1.0.32 fixed the issue with ws.ping().

root-io avatar Mar 18 '24 23:03 root-io

Tried setting up bun again with apollo but when running the subscription I get this error as a subscription message: Cannot instantiate an arrow function which is hard to debug as I don't know where it's coming from. Has anyone else being able to use Apollo with subscriptions?

acrogenesis avatar Apr 09 '24 15:04 acrogenesis

Errors are gone but connections are not stable and I don't know where to start debugging as it works well using Node

Akumzy avatar Apr 09 '24 15:04 Akumzy

Current situation:

  • No error displayed
  • Message received from subscription, but not updated every second

The message should be received every second, but now every 26-28 seconds.

image

Bun Version: 1.1.3

OS: MacOS Arm

On Windows the server won't start at all.

HuakunShen avatar Apr 11 '24 00:04 HuakunShen

Fixed in v1.1.18!

https://github.com/oven-sh/bun/discussions/12327

HuakunShen avatar Jul 04 '24 01:07 HuakunShen

Fixed in v1.1.18!

#12327 I got this error instead after upgrading to 1.1.18 image

Rathpanha avatar Jul 09 '24 09:07 Rathpanha