@@ -58,27 +58,23 @@ type AvailableExport = Pick<StoredExport, "exportName" | "exportURI" | "exportPa
5858export type ExportsManagerConfig = Pick < UserConfig , "exportsPath" | "exportTimeoutMs" | "exportCleanupIntervalMs" > ;
5959
6060type ExportsManagerEvents = {
61+ initialized : [ ] ;
6162 "export-expired" : [ string ] ;
6263 "export-available" : [ string ] ;
6364} ;
6465
6566export class ExportsManager extends EventEmitter < ExportsManagerEvents > {
67+ private wasInitialized : boolean = false ;
6668 private storedExports : Record < StoredExport [ "exportName" ] , StoredExport > = { } ;
6769 private exportsCleanupInProgress : boolean = false ;
68- private exportsCleanupInterval : NodeJS . Timeout ;
69- private exportsDirectoryPath : string ;
70+ private exportsCleanupInterval ?: NodeJS . Timeout ;
7071
71- constructor (
72- sessionId : string ,
72+ private constructor (
73+ private readonly exportsDirectoryPath : string ,
7374 private readonly config : ExportsManagerConfig ,
7475 private readonly logger : LoggerBase
7576 ) {
7677 super ( ) ;
77- this . exportsDirectoryPath = path . join ( this . config . exportsPath , sessionId ) ;
78- this . exportsCleanupInterval = setInterval (
79- ( ) => void this . cleanupExpiredExports ( ) ,
80- this . config . exportCleanupIntervalMs
81- ) ;
8278 }
8379
8480 public get availableExports ( ) : AvailableExport [ ] {
@@ -96,6 +92,24 @@ export class ExportsManager extends EventEmitter<ExportsManagerEvents> {
9692 } ) ) ;
9793 }
9894
95+ protected async init ( ) : Promise < void > {
96+ if ( ! this . wasInitialized ) {
97+ // If a server is killed, the exports from the active session on
98+ // that server won't be cleaned up. We tackle that by attempting to
99+ // clean any directory on the exportsPath when the server starts and
100+ // initializes the ExportsManager.
101+ await this . cleanupOrphanExportsDirectories ( ) ;
102+
103+ this . exportsCleanupInterval = setInterval (
104+ ( ) => void this . cleanupExpiredExports ( ) ,
105+ this . config . exportCleanupIntervalMs
106+ ) ;
107+
108+ this . wasInitialized = true ;
109+ this . emit ( "initialized" ) ;
110+ }
111+ }
112+
99113 public async close ( ) : Promise < void > {
100114 try {
101115 clearInterval ( this . exportsCleanupInterval ) ;
@@ -302,6 +316,25 @@ export class ExportsManager extends EventEmitter<ExportsManagerEvents> {
302316 }
303317 }
304318 }
319+
320+ private async cleanupOrphanExportsDirectories ( ) : Promise < void > {
321+ try {
322+ await fs . rm ( this . exportsDirectoryPath , { force : true , recursive : true } ) ;
323+ } catch ( error ) {
324+ this . logger . error ( {
325+ id : LogId . exportInitError ,
326+ context : "Error while cleaning orphan exports" ,
327+ message : error instanceof Error ? error . message : String ( error ) ,
328+ } ) ;
329+ }
330+ }
331+
332+ static init ( sessionId : string , config : ExportsManagerConfig , logger : LoggerBase ) : ExportsManager {
333+ const exportsDirectoryPath = path . join ( config . exportsPath , sessionId ) ;
334+ const exportsManager = new ExportsManager ( exportsDirectoryPath , config , logger ) ;
335+ void exportsManager . init ( ) ;
336+ return exportsManager ;
337+ }
305338}
306339
307340/**
0 commit comments