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",
|
||||
"issueDate": "2025-05-31T18:29:48.329Z",
|
||||
"savedAt": "2025-05-31T18:29:48.330Z"
|
||||
"expiryDate": "2025-08-30T08:04:36.897Z",
|
||||
"issueDate": "2025-06-01T08:04:36.897Z",
|
||||
"savedAt": "2025-06-01T08:04:36.897Z"
|
||||
}
|
@ -249,4 +249,4 @@ tap.test('should not create timers when shutting down', async () => {
|
||||
expect(intervalFired).toBeFalse();
|
||||
});
|
||||
|
||||
tap.start();
|
||||
export default tap.start();
|
@ -403,7 +403,12 @@ export class EnhancedConnectionPool<T> extends LifecycleComponent {
|
||||
const startTime = Date.now();
|
||||
|
||||
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
|
||||
|
@ -9,6 +9,7 @@ export abstract class LifecycleComponent {
|
||||
target: any;
|
||||
event: string;
|
||||
handler: Function;
|
||||
actualHandler?: Function; // The actual handler registered (may be wrapped)
|
||||
once?: boolean;
|
||||
}> = [];
|
||||
private childComponents: Set<LifecycleComponent> = new Set();
|
||||
@ -21,7 +22,11 @@ export abstract class LifecycleComponent {
|
||||
protected setTimeout(handler: Function, timeout: number): NodeJS.Timeout {
|
||||
if (this.isShuttingDown) {
|
||||
// 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 = () => {
|
||||
@ -33,6 +38,12 @@ export abstract class LifecycleComponent {
|
||||
|
||||
const timer = setTimeout(wrappedHandler, timeout);
|
||||
this.timers.add(timer);
|
||||
|
||||
// Allow process to exit even with timer
|
||||
if (typeof timer.unref === 'function') {
|
||||
timer.unref();
|
||||
}
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
@ -42,7 +53,12 @@ export abstract class LifecycleComponent {
|
||||
protected setInterval(handler: Function, interval: number): NodeJS.Timeout {
|
||||
if (this.isShuttingDown) {
|
||||
// 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 = () => {
|
||||
@ -121,11 +137,12 @@ export abstract class LifecycleComponent {
|
||||
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({
|
||||
target,
|
||||
event,
|
||||
handler,
|
||||
actualHandler, // The handler that was actually registered (may be wrapped)
|
||||
once: options?.once
|
||||
});
|
||||
}
|
||||
@ -208,12 +225,15 @@ export abstract class LifecycleComponent {
|
||||
this.intervals.clear();
|
||||
|
||||
// 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
|
||||
if (typeof target.removeListener === 'function') {
|
||||
target.removeListener(event, handler);
|
||||
target.removeListener(event, handlerToRemove);
|
||||
} else if (typeof target.removeEventListener === 'function') {
|
||||
target.removeEventListener(event, handler);
|
||||
target.removeEventListener(event, handlerToRemove);
|
||||
}
|
||||
}
|
||||
this.listeners = [];
|
||||
|
Loading…
x
Reference in New Issue
Block a user