From 6abfa1fa4c7fea0d69c69b254d2e1ca18f19c4bc Mon Sep 17 00:00:00 2001 From: KC Erb Date: Mon, 8 Feb 2021 15:33:53 -0500 Subject: [PATCH] feat: add autoUnref option With autoUnref set to true (default: false), the Socket.IO client will allow the program to exit if there is no other active timer/socket in the event system. ```js const socket = io({ autoUnref: true }); ``` Note: this option only applies to Node.js clients. Related: https://github.com/socketio/socket.io-client/issues/1446 --- lib/manager.ts | 15 ++++++++++ package-lock.json | 18 ++++-------- package.json | 5 +++- test/fixtures/no-unref.ts | 8 ++++++ test/fixtures/unref-during-reconnection.ts | 12 ++++++++ test/fixtures/unref-polling-only.ts | 13 +++++++++ test/fixtures/unref-websocket-only.ts | 13 +++++++++ test/fixtures/unref.ts | 12 ++++++++ test/index.js | 2 ++ test/node.ts | 33 ++++++++++++++++++++++ 10 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/no-unref.ts create mode 100644 test/fixtures/unref-during-reconnection.ts create mode 100644 test/fixtures/unref-polling-only.ts create mode 100644 test/fixtures/unref-websocket-only.ts create mode 100644 test/fixtures/unref.ts create mode 100644 test/node.ts diff --git a/lib/manager.ts b/lib/manager.ts index f1d482972..8953456f7 100644 --- a/lib/manager.ts +++ b/lib/manager.ts @@ -256,6 +256,13 @@ export interface ManagerOptions extends EngineOptions { */ autoConnect: boolean; + /** + * weather we should unref the reconnect timer when it is + * create automatically + * @default false + */ + autoUnref: boolean; + /** * the parser to use. Defaults to an instance of the Parser that ships with socket.io. */ @@ -531,6 +538,10 @@ export class Manager< socket.emit("error", new Error("timeout")); }, timeout); + if (this.opts.autoUnref) { + timer.unref(); + } + this.subs.push(function subDestroy(): void { clearTimeout(timer); }); @@ -769,6 +780,10 @@ export class Manager< }); }, delay); + if (this.opts.autoUnref) { + timer.unref(); + } + this.subs.push(function subDestroy() { clearTimeout(timer); }); diff --git a/package-lock.json b/package-lock.json index 5cdc74c92..a78bfa8a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4571,9 +4571,9 @@ } }, "engine.io-client": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.2.tgz", - "integrity": "sha512-1mwvwKYMa0AaCy+sPgvJ/SnKyO5MJZ1HEeXfA3Rm/KHkHGiYD5bQVq8QzvIrkI01FuVtOdZC5lWdRw1BGXB2NQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.0.0.tgz", + "integrity": "sha512-e6GK0Fqvq45Nu/j7YdIVqXtDPvlsggAcfml3QiEiGdJ1qeh7IQU6knxSN3+yy9BmbnXtIfjo1hK4MFyHKdc9mQ==", "requires": { "base64-arraybuffer": "0.1.4", "component-emitter": "~1.3.0", @@ -4583,7 +4583,6 @@ "parseqs": "0.0.6", "parseuri": "0.0.6", "ws": "~7.4.2", - "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { @@ -4593,9 +4592,9 @@ "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" }, "ws": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", - "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==" + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==" } } }, @@ -13299,11 +13298,6 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 628431c63..7ff2115a3 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "backo2": "~1.0.2", "component-emitter": "~1.3.0", "debug": "~4.3.1", - "engine.io-client": "~4.1.0", + "engine.io-client": "~5.0.0", "parseuri": "0.0.6", "socket.io-parser": "~4.0.4" }, @@ -108,5 +108,8 @@ }, "tsd": { "directory": "test" + }, + "browser": { + "./test/node.ts": false } } diff --git a/test/fixtures/no-unref.ts b/test/fixtures/no-unref.ts new file mode 100644 index 000000000..82d8c0a06 --- /dev/null +++ b/test/fixtures/no-unref.ts @@ -0,0 +1,8 @@ +const io = require("../.."); +const socket = io("http://localhost:3211", { + autoUnref: false, +}); + +setTimeout(() => { + console.log("process should not exit"); +}, 500); diff --git a/test/fixtures/unref-during-reconnection.ts b/test/fixtures/unref-during-reconnection.ts new file mode 100644 index 000000000..d5558d75a --- /dev/null +++ b/test/fixtures/unref-during-reconnection.ts @@ -0,0 +1,12 @@ +const io = require("../.."); +const socket = io("http://localhost:3211", { + autoUnref: true, +}); + +socket.on("open", () => { + console.log("open"); +}); + +setTimeout(() => { + console.log("process should exit now"); +}, 500); diff --git a/test/fixtures/unref-polling-only.ts b/test/fixtures/unref-polling-only.ts new file mode 100644 index 000000000..01419d636 --- /dev/null +++ b/test/fixtures/unref-polling-only.ts @@ -0,0 +1,13 @@ +const io = require("../.."); +const socket = io("http://localhost:3210", { + autoUnref: true, + transports: ["polling"], +}); + +socket.on("open", () => { + console.log("open"); +}); + +setTimeout(() => { + console.log("process should exit now"); +}, 500); diff --git a/test/fixtures/unref-websocket-only.ts b/test/fixtures/unref-websocket-only.ts new file mode 100644 index 000000000..a4e26893a --- /dev/null +++ b/test/fixtures/unref-websocket-only.ts @@ -0,0 +1,13 @@ +const io = require("../.."); +const socket = io("http://localhost:3210", { + autoUnref: true, + transports: ["websocket"], +}); + +socket.on("open", () => { + console.log("open"); +}); + +setTimeout(() => { + console.log("process should exit now"); +}, 500); diff --git a/test/fixtures/unref.ts b/test/fixtures/unref.ts new file mode 100644 index 000000000..8a281d832 --- /dev/null +++ b/test/fixtures/unref.ts @@ -0,0 +1,12 @@ +const io = require("../.."); +const socket = io("http://localhost:3210", { + autoUnref: true, +}); + +socket.on("open", () => { + console.log("open"); +}); + +setTimeout(() => { + console.log("process should exit now"); +}, 500); diff --git a/test/index.js b/test/index.js index daeebf67a..cfaeaf205 100644 --- a/test/index.js +++ b/test/index.js @@ -3,6 +3,8 @@ const { browser } = require("./support/env"); // whitelist some globals to avoid warnings if (browser) { window.mocha.globals(["___eio", "eio_iframe_*"]); +} else { + require("./node.ts"); } require("./url.ts"); diff --git a/test/node.ts b/test/node.ts new file mode 100644 index 000000000..66d3a582d --- /dev/null +++ b/test/node.ts @@ -0,0 +1,33 @@ +const path = require("path"); +const { exec } = require("child_process"); + +describe("autoRef option", () => { + const fixture = (filename) => + process.execPath + " " + path.join(__dirname, "fixtures", filename); + + it("should stop once the timer is triggered", (done) => { + exec(fixture("unref.ts"), done); + }); + + it("should stop once the timer is triggered (even when trying to reconnect)", (done) => { + exec(fixture("unref-during-reconnection.ts"), done); + }); + + it("should stop once the timer is triggered (polling)", (done) => { + exec(fixture("unref-polling-only.ts"), done); + }); + + it("should stop once the timer is triggered (websocket)", (done) => { + exec(fixture("unref-websocket-only.ts"), done); + }); + + it("should not stop with autoUnref set to false", (done) => { + const process = exec(fixture("no-unref.ts"), () => { + done(new Error("should not happen")); + }); + setTimeout(() => { + process.kill(); + done(); + }, 1000); + }); +});