feat(lifecycle-component): enhance lifecycle management with unref support for timers and event listeners
fix(lifecycle-component): store actual event handler for proper cleanup chore(meta): update certificate dates in meta.json
This commit is contained in:
parent
cacc88797a
commit
726d40b9a5
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"expiryDate": "2025-08-29T18:29:48.329Z",
|
"expiryDate": "2025-08-30T08:04:36.897Z",
|
||||||
"issueDate": "2025-05-31T18:29:48.329Z",
|
"issueDate": "2025-06-01T08:04:36.897Z",
|
||||||
"savedAt": "2025-05-31T18:29:48.330Z"
|
"savedAt": "2025-06-01T08:04:36.897Z"
|
||||||
}
|
}
|
@ -249,4 +249,4 @@ tap.test('should not create timers when shutting down', async () => {
|
|||||||
expect(intervalFired).toBeFalse();
|
expect(intervalFired).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.start();
|
export default tap.start();
|
@ -403,7 +403,12 @@ export class EnhancedConnectionPool<T> extends LifecycleComponent {
|
|||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
while (this.activeConnections.size > 0 && Date.now() - startTime < timeout) {
|
while (this.activeConnections.size > 0 && Date.now() - startTime < timeout) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
await new Promise(resolve => {
|
||||||
|
const timer = setTimeout(resolve, 100);
|
||||||
|
if (typeof timer.unref === 'function') {
|
||||||
|
timer.unref();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy all connections
|
// Destroy all connections
|
||||||
|
@ -9,6 +9,7 @@ export abstract class LifecycleComponent {
|
|||||||
target: any;
|
target: any;
|
||||||
event: string;
|
event: string;
|
||||||
handler: Function;
|
handler: Function;
|
||||||
|
actualHandler?: Function; // The actual handler registered (may be wrapped)
|
||||||
once?: boolean;
|
once?: boolean;
|
||||||
}> = [];
|
}> = [];
|
||||||
private childComponents: Set<LifecycleComponent> = new Set();
|
private childComponents: Set<LifecycleComponent> = new Set();
|
||||||
@ -21,7 +22,11 @@ export abstract class LifecycleComponent {
|
|||||||
protected setTimeout(handler: Function, timeout: number): NodeJS.Timeout {
|
protected setTimeout(handler: Function, timeout: number): NodeJS.Timeout {
|
||||||
if (this.isShuttingDown) {
|
if (this.isShuttingDown) {
|
||||||
// Return a dummy timer if shutting down
|
// Return a dummy timer if shutting down
|
||||||
return setTimeout(() => {}, 0);
|
const dummyTimer = setTimeout(() => {}, 0);
|
||||||
|
if (typeof dummyTimer.unref === 'function') {
|
||||||
|
dummyTimer.unref();
|
||||||
|
}
|
||||||
|
return dummyTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrappedHandler = () => {
|
const wrappedHandler = () => {
|
||||||
@ -33,6 +38,12 @@ export abstract class LifecycleComponent {
|
|||||||
|
|
||||||
const timer = setTimeout(wrappedHandler, timeout);
|
const timer = setTimeout(wrappedHandler, timeout);
|
||||||
this.timers.add(timer);
|
this.timers.add(timer);
|
||||||
|
|
||||||
|
// Allow process to exit even with timer
|
||||||
|
if (typeof timer.unref === 'function') {
|
||||||
|
timer.unref();
|
||||||
|
}
|
||||||
|
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +53,12 @@ export abstract class LifecycleComponent {
|
|||||||
protected setInterval(handler: Function, interval: number): NodeJS.Timeout {
|
protected setInterval(handler: Function, interval: number): NodeJS.Timeout {
|
||||||
if (this.isShuttingDown) {
|
if (this.isShuttingDown) {
|
||||||
// Return a dummy timer if shutting down
|
// Return a dummy timer if shutting down
|
||||||
return setInterval(() => {}, interval);
|
const dummyTimer = setInterval(() => {}, interval);
|
||||||
|
if (typeof dummyTimer.unref === 'function') {
|
||||||
|
dummyTimer.unref();
|
||||||
|
}
|
||||||
|
clearInterval(dummyTimer); // Clear immediately since we don't need it
|
||||||
|
return dummyTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrappedHandler = () => {
|
const wrappedHandler = () => {
|
||||||
@ -121,11 +137,12 @@ export abstract class LifecycleComponent {
|
|||||||
throw new Error('Target must support on() or addEventListener()');
|
throw new Error('Target must support on() or addEventListener()');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the original handler in our tracking (not the wrapped one)
|
// Store both the original handler and the actual handler registered
|
||||||
this.listeners.push({
|
this.listeners.push({
|
||||||
target,
|
target,
|
||||||
event,
|
event,
|
||||||
handler,
|
handler,
|
||||||
|
actualHandler, // The handler that was actually registered (may be wrapped)
|
||||||
once: options?.once
|
once: options?.once
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -208,12 +225,15 @@ export abstract class LifecycleComponent {
|
|||||||
this.intervals.clear();
|
this.intervals.clear();
|
||||||
|
|
||||||
// Remove all event listeners
|
// Remove all event listeners
|
||||||
for (const { target, event, handler } of this.listeners) {
|
for (const { target, event, handler, actualHandler } of this.listeners) {
|
||||||
|
// Use actualHandler if available (for wrapped handlers), otherwise use the original handler
|
||||||
|
const handlerToRemove = actualHandler || handler;
|
||||||
|
|
||||||
// All listeners need to be removed, including 'once' listeners that might not have fired
|
// All listeners need to be removed, including 'once' listeners that might not have fired
|
||||||
if (typeof target.removeListener === 'function') {
|
if (typeof target.removeListener === 'function') {
|
||||||
target.removeListener(event, handler);
|
target.removeListener(event, handlerToRemove);
|
||||||
} else if (typeof target.removeEventListener === 'function') {
|
} else if (typeof target.removeEventListener === 'function') {
|
||||||
target.removeEventListener(event, handler);
|
target.removeEventListener(event, handlerToRemove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user