* Forcefully closes the session abruptly without waiting for streams to be * completed naturally. Any streams that are still open will be immediately * destroyed and any queued datagrams will be dropped. If an error is given, * the closed promise will be rejected with that error. If no erro
(error, options)
| 3511 | * string included in the CONNECTION_CLOSE frame (diagnostic only). |
| 3512 | */ |
| 3513 | destroy(error, options) { |
| 3514 | assertIsQuicSession(this); |
| 3515 | const inner = this.#inner; |
| 3516 | // Two distinct guards (see also `QuicStream.destroy`): |
| 3517 | // * `#destroying` flips synchronously here so any re-entrant call |
| 3518 | // (e.g. from a user `onerror` callback or from a cascading |
| 3519 | // `stream.destroy(error)` whose own `onerror` re-enters |
| 3520 | // `session.destroy()`) hits this guard and returns immediately |
| 3521 | // without running the teardown twice. |
| 3522 | // * `destroyed` (i.e. `#handle === undefined`) signals |
| 3523 | // "fully torn down". Defense-in-depth for paths that may have |
| 3524 | // finished teardown without setting `#destroying` and for |
| 3525 | // repeat invocations after this method has fully run. |
| 3526 | if (inner.destroying || this.destroyed) return; |
| 3527 | |
| 3528 | if (options !== undefined) options = validateCloseOptions(options); |
| 3529 | inner.destroying = true; |
| 3530 | |
| 3531 | debug('destroying the session'); |
| 3532 | |
| 3533 | if (error !== undefined) { |
| 3534 | if (onSessionErrorChannel.hasSubscribers) { |
| 3535 | onSessionErrorChannel.publish({ |
| 3536 | __proto__: null, |
| 3537 | session: this, |
| 3538 | error, |
| 3539 | }); |
| 3540 | } |
| 3541 | if (typeof inner.onerror === 'function') { |
| 3542 | invokeOnerror(inner.onerror, error); |
| 3543 | } |
| 3544 | } |
| 3545 | |
| 3546 | // First, forcefully and immediately destroy all open streams, if any. |
| 3547 | for (const stream of inner.streams) { |
| 3548 | stream.destroy(error); |
| 3549 | } |
| 3550 | // The streams should remove themselves when they are destroyed but let's |
| 3551 | // be doubly sure. |
| 3552 | if (inner.streams.size) { |
| 3553 | process.emitWarning( |
| 3554 | `The session is destroyed with ${inner.streams.size} active streams. ` + |
| 3555 | 'This should not happen and indicates a bug in Node.js. Please open an ' + |
| 3556 | 'issue in the Node.js GitHub repository at https://github.com/nodejs/node ' + |
| 3557 | 'to report the problem.', |
| 3558 | ); |
| 3559 | } |
| 3560 | inner.streams.clear(); |
| 3561 | |
| 3562 | // Remove this session immediately from the endpoint |
| 3563 | inner.endpoint[kRemoveSession](this); |
| 3564 | inner.endpoint = undefined; |
| 3565 | inner.isPendingClose = false; |
| 3566 | |
| 3567 | // If the handshake never completed, reject the opened promise. The |
| 3568 | // session is being destroyed, so the handshake will never complete |
| 3569 | // and `await session.opened` would otherwise hang forever. The |
| 3570 | // documented contract is that opened rejects when the session is |
no test coverage detected