@@ -2,6 +2,7 @@ import { app } from "electron";
22import { injectable } from "inversify" ;
33import { ANALYTICS_EVENTS } from "../../../types/analytics.js" ;
44import { container } from "../../di/container.js" ;
5+ import { withTimeout } from "../../lib/async.js" ;
56import { logger } from "../../lib/logger.js" ;
67import { shutdownPostHog , trackAppEvent } from "../posthog-analytics.js" ;
78
@@ -10,6 +11,7 @@ const log = logger.scope("app-lifecycle");
1011@injectable ( )
1112export class AppLifecycleService {
1213 private _isQuittingForUpdate = false ;
14+ private static readonly SHUTDOWN_TIMEOUT_MS = 3000 ;
1315
1416 get isQuittingForUpdate ( ) : boolean {
1517 return this . _isQuittingForUpdate ;
@@ -20,23 +22,33 @@ export class AppLifecycleService {
2022 }
2123
2224 async shutdown ( ) : Promise < void > {
23- log . info ( "Performing graceful shutdown..." ) ;
25+ // Race shutdown against timeout to prevent app from hanging forever
26+ const result = await withTimeout (
27+ this . doShutdown ( ) ,
28+ AppLifecycleService . SHUTDOWN_TIMEOUT_MS ,
29+ ) ;
30+
31+ if ( result . result === "timeout" ) {
32+ log . warn ( "Shutdown timeout reached, proceeding anyway" , {
33+ timeoutMs : AppLifecycleService . SHUTDOWN_TIMEOUT_MS ,
34+ } ) ;
35+ }
36+ }
2437
38+ private async doShutdown ( ) : Promise < void > {
2539 try {
2640 await container . unbindAll ( ) ;
2741 } catch ( error ) {
28- log . error ( "Error during container unbind" , error ) ;
42+ log . error ( "Failed to unbind container " , error ) ;
2943 }
3044
3145 trackAppEvent ( ANALYTICS_EVENTS . APP_QUIT ) ;
3246
3347 try {
3448 await shutdownPostHog ( ) ;
3549 } catch ( error ) {
36- log . error ( "Error shutting down PostHog" , error ) ;
50+ log . error ( "Failed to shutdown PostHog" , error ) ;
3751 }
38-
39- log . info ( "Graceful shutdown complete" ) ;
4052 }
4153
4254 async shutdownAndExit ( ) : Promise < void > {
0 commit comments