1- import { existsSync , mkdirSync } from 'fs' ;
1+ import { existsSync , mkdirSync , readdirSync , rmSync } from 'fs' ;
22import { join } from 'path' ;
33import { Logger } from 'pino' ;
44import { LoggerFactory } from '../telemetry/LoggerFactory' ;
@@ -13,27 +13,40 @@ export class FileStoreFactory implements DataStoreFactory {
1313 @Telemetry ( { scope : 'FileStore.Global' } ) private readonly telemetry ! : ScopedTelemetry ;
1414
1515 private readonly stores = new Map < StoreName , EncryptedFileStore > ( ) ;
16+ private readonly fileDbRoot : string ;
1617 private readonly fileDbDir : string ;
18+
1719 private readonly metricsInterval : NodeJS . Timeout ;
20+ private readonly timeout : NodeJS . Timeout ;
1821
1922 constructor ( rootDir : string ) {
2023 this . log = LoggerFactory . getLogger ( 'FileStore.Global' ) ;
2124
22- this . fileDbDir = join ( rootDir , 'filedb' , `${ Version } ` ) ;
25+ this . fileDbRoot = join ( rootDir , 'filedb' ) ;
26+ this . fileDbDir = join ( this . fileDbRoot , Version ) ;
27+
2328 if ( ! existsSync ( this . fileDbDir ) ) {
2429 mkdirSync ( this . fileDbDir , { recursive : true } ) ;
2530 }
2631
2732 this . metricsInterval = setInterval ( ( ) => {
2833 this . emitMetrics ( ) ;
2934 } , 60 * 1000 ) ;
30- this . log . info ( `Initialized FileStore v${ Version } ` ) ;
35+
36+ this . timeout = setTimeout (
37+ ( ) => {
38+ this . cleanupOldVersions ( ) ;
39+ } ,
40+ 2 * 60 * 1000 ,
41+ ) ;
42+
43+ this . log . info ( `Initialized FileDB ${ Version } ` ) ;
3144 }
3245
3346 get ( store : StoreName ) : DataStore {
3447 let val = this . stores . get ( store ) ;
3548 if ( ! val ) {
36- val = new EncryptedFileStore ( encryptionKey ( Version ) , store , this . fileDbDir ) ;
49+ val = new EncryptedFileStore ( encryptionKey ( VersionNumber ) , store , this . fileDbDir ) ;
3750 this . stores . set ( store , val ) ;
3851 }
3952 return val ;
@@ -44,12 +57,13 @@ export class FileStoreFactory implements DataStoreFactory {
4457 }
4558
4659 close ( ) : Promise < void > {
60+ clearTimeout ( this . timeout ) ;
4761 clearInterval ( this . metricsInterval ) ;
4862 return Promise . resolve ( ) ;
4963 }
5064
5165 private emitMetrics ( ) : void {
52- this . telemetry . histogram ( 'version' , Version ) ;
66+ this . telemetry . histogram ( 'version' , VersionNumber ) ;
5367 this . telemetry . histogram ( 'env.entries' , this . stores . size ) ;
5468
5569 let totalBytes = 0 ;
@@ -67,6 +81,22 @@ export class FileStoreFactory implements DataStoreFactory {
6781 unit : 'By' ,
6882 } ) ;
6983 }
84+
85+ private cleanupOldVersions ( ) : void {
86+ const entries = readdirSync ( this . fileDbRoot , { withFileTypes : true } ) ;
87+ for ( const entry of entries ) {
88+ try {
89+ if ( entry . name !== Version ) {
90+ this . telemetry . count ( 'oldVersion.cleanup.count' , 1 ) ;
91+ rmSync ( join ( this . fileDbRoot , entry . name ) , { recursive : true , force : true } ) ;
92+ }
93+ } catch ( error ) {
94+ this . log . error ( error , 'Failed to cleanup old FileDB versions' ) ;
95+ this . telemetry . count ( 'oldVersion.cleanup.error' , 1 ) ;
96+ }
97+ }
98+ }
7099}
71100
72- const Version = 1 ;
101+ const VersionNumber = 2 ;
102+ const Version = `v${ VersionNumber } ` ;
0 commit comments