Disconnect handler not executed if connection drops during middleware execution
See original GitHub issueDescribe the bug If I use a middleware (e.g. for authentication) I cannot handle a client disconnect because
disconnect
event-handler does not get executedsocket.connected
won’t update properly (fromtrue
tofalse
)
To Reproduce
Please fill the following code example:
Socket.IO server version: 4.2.0
Server
import { Server } from "socket.io";
const io = new Server(3000, {});
io.use(async (socket, next) => {
console.log(`middleware`, socket.id);
// bug 1: disconnect handler will never execute
socket.on("disconnect", () => {
console.log(`disconnect ${socket.id}`);
});
// long running async operation
// client will disconnect before operation has finished
await new Promise(resolve => setTimeout(resolve, 3000));
// bug 2: connected state is still true
console.log(`still connected: ${socket.connected}`);
next();
});
io.on("connection", (socket) => {
console.log(`connect ${socket.id}`);
});
Socket.IO client version: 4
Client
import { io } from "socket.io-client";
const socket = io("ws://localhost:3000/", {});
// force disconnect before long running operation has finished
setTimeout(window.location.reload, 1000);
Expected behavior
socket.connected
will update properly and disconnect
event-handler will run
Platform: node.js 16 on macOS
Additional context
The workaround to the problem is: don’t trigger side-effects in middleware and always add custom properties to the socket object to transfer information over to connection
event-handler
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (2 by maintainers)
Top Results From Across the Web
Connecting and disconnecting (Concepts) - Prisma
PrismaClient connects and disconnects from your data source using the following two methods: $connect() $disconnect()
Read more >Redux saga not working after network reconnection
I noticed that if the user lost its network connection and execute the action, the saga will handle it on the catch block...
Read more >Handle errors in ASP.NET Core | Microsoft Learn
In ASP.NET Core apps, the following middleware generates problem details HTTP responses when AddProblemDetails is called, except when the Accept ...
Read more >API Reference: ApolloServer - Apollo GraphQL Docs
Transitions the server to a state where it will not start executing more GraphQL operations. Calls and awaits all serverWillStop plugin handlers (including...
Read more >Middlewares | Socket.IO
Important note: the Socket instance is not actually connected when the middleware gets executed, which means that no disconnect event will ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@kkleap If you use the middleware to trigger a side effect, you sometimes need to trigger a cleanup for that effect after the client has disconnected.
Proper example:
Server
This implementation will leave the sessions object in a corrupt state if the client disconnects early, because
socket.connected
is always true and the disconnect handler will not register.Even if you “lift” the register of the disconnect handler like so:
The sessions object will still end up corrupted cause the disconnect handler won’t fire.
So please fix the implementation to either properly update the connected property (would be my favorite) or just trigger the disconnect handler.
Edit: For the sake of completeness. Yes, you could circumvent the problem in the example by doing something like this:
However, it feels wrong to rely on patching objects you don’t “own”. Also this won’t help if you need to track clients that are in a pending state for instance. (E.g. 2FA)
Edit2: @darrachequesne listening for the “close” event on the underlying connection seems to be a great solution. Thanks for the contribution. Nevertheless, I still think that the socket.connected property should be properly updated and set to false on early disconnect or is not set to true before the “connection” event is fired.
Hmm, yes, totally, you are right, we need to change that.
The connection can indeed be closed during the middleware execution (here).
Two possibilities: