mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-08 22:48:20 -05:00
fix(eio): discard all pending packets when the server is closed
In some specific cases, the transport was not closed right away,
leaving the Node.js process alive even after closing the server.
The HTTP long-polling transport would be closed after the heartbeat
failure and the `closeTimeout` delay (20 + 25 + 30 seconds).
Example:
```js
io.on("connection", (socket) => {
// the writeBuffer is not empty, so the transport is not closed right away
io.close();
});
```
Related: https://github.com/socketio/socket.io/issues/5088
This commit is contained in:
@@ -554,6 +554,13 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} for chaining
|
||||
*/
|
||||
public close(discard?: boolean) {
|
||||
if (
|
||||
discard &&
|
||||
(this.readyState === "open" || this.readyState === "closing")
|
||||
) {
|
||||
return this.closeTransport(discard);
|
||||
}
|
||||
|
||||
if ("open" !== this.readyState) return;
|
||||
|
||||
this.readyState = "closing";
|
||||
@@ -570,7 +577,7 @@ export class Socket extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
debug("the buffer is empty, closing the transport right away", discard);
|
||||
debug("the buffer is empty, closing the transport right away");
|
||||
this.closeTransport(discard);
|
||||
}
|
||||
|
||||
@@ -581,7 +588,7 @@ export class Socket extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
private closeTransport(discard: boolean) {
|
||||
debug("closing the transport (discard? %s)", discard);
|
||||
debug("closing the transport (discard? %s)", !!discard);
|
||||
if (discard) this.transport.discard();
|
||||
this.transport.close(this.onClose.bind(this, "forced close"));
|
||||
}
|
||||
|
||||
@@ -1634,6 +1634,67 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server (2)", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close(); // readyState is now "closing"
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should not discard the packets in the writeBuffer when closing gracefully", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", (val) => {
|
||||
expect(val).to.eql("hello");
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("graceful close", () => {
|
||||
before(function () {
|
||||
if (process.env.EIO_WS_ENGINE === "uws") {
|
||||
|
||||
Reference in New Issue
Block a user