Skip to content

Commit

Permalink
net: server add asyncDispose
Browse files Browse the repository at this point in the history
PR-URL: #48717
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
  • Loading branch information
atlowChemi authored and ruyadorno committed Sep 12, 2023
1 parent bf75a11 commit 45c7e5e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 1 deletion.
11 changes: 11 additions & 0 deletions doc/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,17 @@ The optional `callback` will be called once the `'close'` event occurs. Unlike
that event, it will be called with an `Error` as its only argument if the server
was not open when it was closed.

### `server[Symbol.asyncDispose]()`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental
Calls [`server.close()`][] and returns a promise that fulfills when the
server has closed.

### `server.getConnections(callback)`

<!-- YAML
Expand Down
11 changes: 10 additions & 1 deletion lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const {
ArrayPrototypePush,
Boolean,
FunctionPrototypeBind,
FunctionPrototypeCall,
MathMax,
Number,
NumberIsNaN,
Expand All @@ -35,6 +36,7 @@ const {
ObjectSetPrototypeOf,
Symbol,
ObjectCreate,
SymbolAsyncDispose,
} = primordials;

const EventEmitter = require('events');
Expand Down Expand Up @@ -110,7 +112,7 @@ const {
} = require('internal/errors');
const { isUint8Array } = require('internal/util/types');
const { queueMicrotask } = require('internal/process/task_queues');
const { kEmptyObject } = require('internal/util');
const { kEmptyObject, promisify } = require('internal/util');
const {
validateAbortSignal,
validateBoolean,
Expand Down Expand Up @@ -2191,6 +2193,13 @@ Server.prototype.close = function(cb) {
return this;
};

Server.prototype[SymbolAsyncDispose] = async function() {
if (!this._handle) {
return;
}
return FunctionPrototypeCall(promisify(this.close), this);
};

Server.prototype._emitCloseIfDrained = function() {
debug('SERVER _emitCloseIfDrained');

Expand Down
30 changes: 30 additions & 0 deletions test/parallel/test-net-server-async-dispose.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as common from '../common/index.mjs';
import assert from 'node:assert';
import net from 'node:net';
import { describe, it } from 'node:test';

describe('net.Server[Symbol.asyncDispose]()', () => {
it('should close the server', async () => {
const server = net.createServer();
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);

server.listen(0, common.mustCall(async () => {
await server[Symbol.asyncDispose]().then(common.mustCall());
assert.strictEqual(server.address(), null);
clearTimeout(timeoutRef);
}));

server.on('close', common.mustCall());
});

it('should resolve even if the server is already closed', async () => {
const server = net.createServer();
const timeoutRef = setTimeout(common.mustNotCall(), 2 ** 31 - 1);

server.listen(0, common.mustCall(async () => {
await server[Symbol.asyncDispose]().then(common.mustCall());
await server[Symbol.asyncDispose]().then(common.mustCall(), common.mustNotCall());
clearTimeout(timeoutRef);
}));
});
});

0 comments on commit 45c7e5e

Please sign in to comment.