hapijs / nes

WebSocket adapter plugin for hapi routes
Other
502 stars 87 forks source link

Cannot get pub/sub example to work #309

Closed rgov closed 4 years ago

rgov commented 4 years ago

Support plan

Context

How can we help?

I'm just trying to run the subscription sample code here.

If I use the code unmodified, I get from the client:

(node:26349) UnhandledPromiseRejectionWarning: Error: Connection terminated while waiting to connect

Perhaps the default port is 80, and I'm not running as root, but then I'd expect the server script to tell me it cannot bind to the desired port? It says nothing.

Anyway, if I modify the server and client to specify a host and port, then the connection succeeds:

const server = new Hapi.Server({ address: "localhost", port: 1555 });
const client = new Nes.Client('ws://localhost:1555');

The client example doesn't do anything when a message is received, so I added a console.log("foo") call to it.

Yet the callback never seems to get fired. Is something missing from the examples or my setup?

I know that the server is getting the subscription because I can add an onSubscribe callback. If I add a filter callback it doesn't appear to be called. I don't know if there is a race condition where the messages are published before the client connects or something, but I also tried sending a message in the onSubscribe callback and that didn't work either.

For what it's worth, the route invocation example code works fine (with port change).

rgov commented 4 years ago

I might be correct about the race condition issue. If I change it to:

    setInterval(async () => {
        await server.publish('/item/5', { id: 5, status: 'complete' });
    }, 1000);

Then messages go through, the filter callback fires, the client's handler fires, etc.

Can the example be updated to something that works properly?

nazreen commented 4 years ago

@rgov in my own development, I was stumped for 15 minutes simply because I was using nodemon for both server and client and thus the client was trying to connect when the connection has not been established yet. restarting the client after the server is up works. this point should be mentioned in the example.

hueniverse commented 4 years ago

Unfortunately, no community resources were available to help resolve this issue after two weeks, and it is being closed. We close unresolved community issues to keep the issue tracker organized and effective. Please check https://hapi.dev/support for other support options.

nazreen commented 4 years ago

the issue can be fixed by clarifying in the docs that the server and client shouldn't be in the same file or started at the same time, which is a 'no brainer' when you think about it, but is very easily overlooked when you're following docs and trying to get something to work the first time.

rgov commented 4 years ago

I don't think they were in the same file, but it's been a while. That said I'm not sure why it should matter if they're in separate files, it's supposed to support concurrency, right?

Re-reading my bug report, I think there are at least 3 things wrong with the example (and/or the module) from my post.

It makes sense that the client can only connect after the server is listening, of course, but the fact that publishing a message didn't work in onSubscribe but did after a 5 second timer suggests something weird about what's going on behind the scenes.

nazreen commented 4 years ago

yes it's not the fact that it's in the same file that's the issue, just that starting up the client in the line right after starting the server will most likely result in this issue since not enough time has passed since the server was started.

was it 5 seconds? your comment above has 1000 miliseconds, which was what I was able to replicate too.

devinivy commented 4 years ago

Here is a working example that doesn't rely on a race. In short, you should start the server before connecting the client, and let the subscription complete before having the server publish.


const Hapi = require('@hapi/hapi');
const Nes = require('@hapi/nes');

(async () => {

    const server = new Hapi.Server();
    const client = new Nes.Client('ws://localhost');

    await server.register(Nes);
    server.subscription('/item/{id}');

    await server.start();
    await client.connect();

    const handler = (update, flags) => {

        // update -> { id: 5, status: 'complete' }
        // Second publish is not received (doesn't match)
    };

    await client.subscribe('/item/5', handler);

    server.publish('/item/5', { id: 5, status: 'complete' });
    server.publish('/item/6', { id: 6, status: 'initial' });
})();