process: port on-exit-leak-free to core · nodejs/node@77936c3 · GitHub
Skip to content

Commit 77936c3

Browse files
H4adaduh95
authored andcommitted
process: port on-exit-leak-free to core
PR-URL: #53239 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
1 parent a1a5ad8 commit 77936c3

12 files changed

Lines changed: 569 additions & 1 deletion

File tree

LICENSE

Lines changed: 25 additions & 0 deletions

doc/api/process.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,219 @@ a code.
18891889
Specifying a code to [`process.exit(code)`][`process.exit()`] will override any
18901890
previous setting of `process.exitCode`.
18911891
1892+
## `process.finalization.register(ref, callback)`
1893+
1894+
<!-- YAML
1895+
added: REPLACEME
1896+
-->
1897+
1898+
> Stability: 1.1 - Active Development
1899+
1900+
* `ref` {Object | Function} The reference to the resource that is being tracked.
1901+
* `callback` {Function} The callback function to be called when the resource
1902+
is finalized.
1903+
* `ref` {Object | Function} The reference to the resource that is being tracked.
1904+
* `event` {string} The event that triggered the finalization. Defaults to 'exit'.
1905+
1906+
This function registers a callback to be called when the process emits the `exit`
1907+
event if the `ref` object was not garbage collected. If the object `ref` was garbage collected
1908+
before the `exit` event is emitted, the callback will be removed from the finalization registry,
1909+
and it will not be called on process exit.
1910+
1911+
Inside the callback you can release the resources allocated by the `ref` object.
1912+
Be aware that all limitations applied to the `beforeExit` event are also applied to the `callback` function,
1913+
this means that there is a possibility that the callback will not be called under special circumstances.
1914+
1915+
The idea of ​​this function is to help you free up resources when the starts process exiting,
1916+
but also let the object be garbage collected if it is no longer being used.
1917+
1918+
Eg: you can register an object that contains a buffer, you want to make sure that buffer is released
1919+
when the process exit, but if the object is garbage collected before the process exit, we no longer
1920+
need to release the buffer, so in this case we just remove the callback from the finalization registry.
1921+
1922+
```cjs
1923+
const { finalization } = require('node:process');
1924+
1925+
// Please make sure that the function passed to finalization.register()
1926+
// does not create a closure around unnecessary objects.
1927+
function onFinalize(obj, event) {
1928+
// You can do whatever you want with the object
1929+
obj.dispose();
1930+
}
1931+
1932+
function setup() {
1933+
// This object can be safely garbage collected,
1934+
// and the resulting shutdown function will not be called.
1935+
// There are no leaks.
1936+
const myDisposableObject = {
1937+
dispose() {
1938+
// Free your resources synchronously
1939+
},
1940+
};
1941+
1942+
finalization.register(myDisposableObject, onFinalize);
1943+
}
1944+
1945+
setup();
1946+
```
1947+
1948+
```mjs
1949+
import { finalization } from 'node:process';
1950+
1951+
// Please make sure that the function passed to finalization.register()
1952+
// does not create a closure around unnecessary objects.
1953+
function onFinalize(obj, event) {
1954+
// You can do whatever you want with the object
1955+
obj.dispose();
1956+
}
1957+
1958+
function setup() {
1959+
// This object can be safely garbage collected,
1960+
// and the resulting shutdown function will not be called.
1961+
// There are no leaks.
1962+
const myDisposableObject = {
1963+
dispose() {
1964+
// Free your resources synchronously
1965+
},
1966+
};
1967+
1968+
finalization.register(myDisposableObject, onFinalize);
1969+
}
1970+
1971+
setup();
1972+
```
1973+
1974+
The code above relies on the following assumptions:
1975+
1976+
* arrow functions are avoided
1977+
* regular functions are recommended to be within the global context (root)
1978+
1979+
Regular functions _could_ reference the context where the `obj` lives, making the `obj` not garbage collectible.
1980+
1981+
Arrow functions will hold the previous context. Consider, for example:
1982+
1983+
```js
1984+
class Test {
1985+
constructor() {
1986+
finalization.register(this, (ref) => ref.dispose());
1987+
1988+
// even something like this is highly discouraged
1989+
// finalization.register(this, () => this.dispose());
1990+
}
1991+
dispose() {}
1992+
}
1993+
```
1994+
1995+
It is very unlikely (not impossible) that this object will be garbage collected,
1996+
but if it is not, `dispose` will be called when `process.exit` is called.
1997+
1998+
Be careful and avoid relying on this feature for the disposal of critical resources,
1999+
as it is not guaranteed that the callback will be called under all circumstances.
2000+
2001+
## `process.finalization.registerBeforeExit(ref, callback)`
2002+
2003+
<!-- YAML
2004+
added: REPLACEME
2005+
-->
2006+
2007+
> Stability: 1.1 - Active Development
2008+
2009+
* `ref` {Object | Function} The reference
2010+
to the resource that is being tracked.
2011+
* `callback` {Function} The callback function to be called when the resource
2012+
is finalized.
2013+
* `ref` {Object | Function} The reference to the resource that is being tracked.
2014+
* `event` {string} The event that triggered the finalization. Defaults to 'beforeExit'.
2015+
2016+
This function behaves exactly like the `register`, except that the callback will be called
2017+
when the process emits the `beforeExit` event if `ref` object was not garbage collected.
2018+
2019+
Be aware that all limitations applied to the `beforeExit` event are also applied to the `callback` function,
2020+
this means that there is a possibility that the callback will not be called under special circumstances.
2021+
2022+
## `process.finalization.unregister(ref)`
2023+
2024+
<!-- YAML
2025+
added: REPLACEME
2026+
-->
2027+
2028+
> Stability: 1.1 - Active Development
2029+
2030+
* `ref` {Object | Function} The reference
2031+
to the resource that was registered previously.
2032+
2033+
This function remove the register of the object from the finalization
2034+
registry, so the callback will not be called anymore.
2035+
2036+
```cjs
2037+
const { finalization } = require('node:process');
2038+
2039+
// Please make sure that the function passed to finalization.register()
2040+
// does not create a closure around unnecessary objects.
2041+
function onFinalize(obj, event) {
2042+
// You can do whatever you want with the object
2043+
obj.dispose();
2044+
}
2045+
2046+
function setup() {
2047+
// This object can be safely garbage collected,
2048+
// and the resulting shutdown function will not be called.
2049+
// There are no leaks.
2050+
const myDisposableObject = {
2051+
dispose() {
2052+
// Free your resources synchronously
2053+
},
2054+
};
2055+
2056+
finalization.register(myDisposableObject, onFinalize);
2057+
2058+
// Do something
2059+
2060+
myDisposableObject.dispose();
2061+
finalization.unregister(myDisposableObject);
2062+
}
2063+
2064+
setup();
2065+
```
2066+
2067+
```mjs
2068+
import { finalization } from 'node:process';
2069+
2070+
// Please make sure that the function passed to finalization.register()
2071+
// does not create a closure around unnecessary objects.
2072+
function onFinalize(obj, event) {
2073+
// You can do whatever you want with the object
2074+
obj.dispose();
2075+
}
2076+
2077+
function setup() {
2078+
// This object can be safely garbage collected,
2079+
// and the resulting shutdown function will not be called.
2080+
// There are no leaks.
2081+
const myDisposableObject = {
2082+
dispose() {
2083+
// Free your resources synchronously
2084+
},
2085+
};
2086+
2087+
// Please make sure that the function passed to finalization.register()
2088+
// does not create a closure around unnecessary objects.
2089+
function onFinalize(obj, event) {
2090+
// You can do whatever you want with the object
2091+
obj.dispose();
2092+
}
2093+
2094+
finalization.register(myDisposableObject, onFinalize);
2095+
2096+
// Do something
2097+
2098+
myDisposableObject.dispose();
2099+
finalization.unregister(myDisposableObject);
2100+
}
2101+
2102+
setup();
2103+
```
2104+
18922105
## `process.getActiveResourcesInfo()`
18932106
18942107
<!-- YAML

lib/internal/bootstrap/node.js

Lines changed: 20 additions & 0 deletions

0 commit comments

Comments
 (0)