Node js socket io connection fails when two machines are running

So i have a node js app that uses socket io. Locally everything works perfectly and it also works perfectly when only one instance/machine is running. Once the second machine starts running on fly i get websocket connection failed: WebSocket is closed before the connection is established.

My fly.toml is pretty much the default.

I assume this has to do with the configuration, any ideas?

I have a hunch! It might be related to being routed in between machines. This topic below talks about it and has an example repo:

If that is not enough, can you try debugging with this? Troubleshooting connection issues | Socket.IO

So i think you are right but i haven’t figured it out yet. Here’s what i tried:

Server:
const FLY_INSTANCE_ID = process.env.FLY_ALLOC_ID
? process.env.FLY_ALLOC_ID.split(“-”)[0]
: null;

app.get(‘/menue’, (req, res) => {
res.cookie(‘mid’, FLY_INSTANCE_ID, {maxAge: 604800000})
res.render(‘menue’)
})

http.on(“upgrade”, function (req, socket, head) {
// No-op on localhost/non-Fly environments.
if (!FLY_INSTANCE_ID) return;

// No-op on other HTTP upgrades.
if (req.headers[“upgrade”] !== “websocket”) return;

// Get target fly instance via URL pattern matching.
const instanceIdMatches = req.url.match(/fly_instance_id=(.*?)(?:&|$)/);
// No matches, bail.
if (!instanceIdMatches) return;
const TARGET_INSTANCE = instanceIdMatches[1];

if (FLY_INSTANCE_ID === TARGET_INSTANCE) return;
console.log(“Mismatch detected, replaying”,FLY_INSTANCE_ID);
console.log(TARGET_INSTANCE)

// Create a raw HTTP response with the fly-replay header.
// HTTP code 101 must be used to make the response replay correctly.
const headers = [
“HTTP/1.1 101 Switching Protocols”,
fly-replay: instance=${TARGET_INSTANCE},
];

// Send new headers and close the socket.
socket.end(headers.concat(“\r\n”).join(“\r\n”));
});

const io = require(‘socket.io’)(http)

Client:
const socket = io({
query: { fly_instance_id: getCookie(“mid”) },
extraHeaders: { “fly-force-instance-id”: getCookie(“mid”) }
});

Sometimes it works, probably when the socket connects to the correct machine but when i get a missmatch the server prints the console log missmatch but it doesn’t work. Any ideas?

Edit: I’m still trying to figure this out, the logs for the tow machines seem strange to me, i try to connect only one client and when i get a mismatch i get a connection on the other machine but the first machine also logs “connected” or in other cases the correct machine gets more than one connections. In both of these cases i get failed connection

Could you clarify if you are in SSR environment or pure client side js environment?

pure client side env

if you are in pure client side js environment, your code may not be executing in the correct order.

it looks like you are setting cookie ‘mid’ on GET request.

Your client code

const socket = io({
query: { fly_instance_id: getCookie(“mid”) },
extraHeaders: { “fly-force-instance-id”: getCookie(“mid”) }
});

should run AFTER the GET request responds and sets the “mid” cookie properly.
if not, getCooke("mid") won’t give you the result you’d expect.

SSR env

you should not need cookie passing since FLY_INSTANCE_ID should be available during your initial server-side rendering phase from the server environment variable.

Thanks for the response (sorry i didn’t respond earlier, i was away for work), i think i’m on client side env (page contenet is generated on the clients side with data aquired from the server). The client side code for the socket is the first thing to execute on the client side js file so you might be right but the confusing thing is that on the server side the instance id the client includes in the socket connection seems to be retrieved correctly from the cookie (i console log it in the server code above). Also i actually think i will have to replay the get requests for some clients too but that’s a different topic in itself.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.