@@ -69,12 +69,65 @@ async function process_expiry() {
6969 const fs_context = native_fs_utils . get_process_fs_context ( ) ;
7070
7171 await lock_and_run ( fs_context , SCAN_LOCK , async ( ) => {
72- if ( ! ( await time_exceeded ( fs_context , config . NSFS_GLACIER_EXPIRY_INTERVAL , GlacierBackend . EXPIRY_TIMESTAMP_FILE ) ) ) return ;
72+ const backend = getGlacierBackend ( ) ;
73+ if (
74+ await backend . low_free_space ( ) ||
75+ await is_desired_time (
76+ fs_context ,
77+ new Date ( ) ,
78+ config . NSFS_GLACIER_EXPIRY_RUN_TIME ,
79+ config . NSFS_GLACIER_EXPIRY_RUN_DELAY_LIMIT_MINS ,
80+ GlacierBackend . EXPIRY_TIMESTAMP_FILE ,
81+ )
82+ ) {
83+ await backend . expiry ( fs_context ) ;
84+ await record_current_time ( fs_context , GlacierBackend . EXPIRY_TIMESTAMP_FILE ) ;
85+ }
86+ } ) ;
87+ }
7388
89+ /**
90+ * is_desired_time returns true if the given time matches with
91+ * the desired time or if
92+ * @param {nb.NativeFSContext } fs_context
93+ * @param {Date } current
94+ * @param {string } desire time in format 'hh:mm'
95+ * @param {number } delay_limit_mins
96+ * @param {string } timestamp_file
97+ * @returns {Promise<boolean> }
98+ */
99+ async function is_desired_time ( fs_context , current , desire , delay_limit_mins , timestamp_file ) {
100+ const [ desired_hour , desired_min ] = desire . split ( ':' ) . map ( Number ) ;
101+ if (
102+ isNaN ( desired_hour ) ||
103+ isNaN ( desired_min ) ||
104+ ( desired_hour < 0 || desired_hour >= 24 ) ||
105+ ( desired_min < 0 || desired_min >= 60 )
106+ ) {
107+ throw new Error ( 'invalid desired_time - must be hh:mm' ) ;
108+ }
74109
75- await getGlacierBackend ( ) . expiry ( fs_context ) ;
76- await record_current_time ( fs_context , GlacierBackend . EXPIRY_TIMESTAMP_FILE ) ;
77- } ) ;
110+ const min_time = get_tz_date ( desired_hour , desired_min , 0 , config . NSFS_GLACIER_EXPIRY_TZ ) ;
111+ const max_time = get_tz_date ( desired_hour , desired_min + delay_limit_mins , 0 , config . NSFS_GLACIER_EXPIRY_TZ ) ;
112+
113+ if ( current >= min_time && current <= max_time ) {
114+ try {
115+ const { data } = await nb_native ( ) . fs . readFile ( fs_context , path . join ( config . NSFS_GLACIER_LOGS_DIR , timestamp_file ) ) ;
116+ const lastrun = new Date ( data . toString ( ) ) ;
117+
118+ // Last run should NOT be in this window
119+ if ( lastrun >= min_time && lastrun <= max_time ) return false ;
120+ } catch ( error ) {
121+ if ( error . code === 'ENOENT' ) return true ;
122+ console . error ( 'failed to read last run timestamp:' , error , 'timestamp_file:' , timestamp_file ) ;
123+
124+ throw error ;
125+ }
126+
127+ return true ;
128+ }
129+
130+ return false ;
78131}
79132
80133/**
@@ -134,6 +187,31 @@ async function run_glacier_operation(fs_context, log_namespace, cb) {
134187 }
135188}
136189
190+ /**
191+ * @param {number } hours
192+ * @param {number } mins
193+ * @param {number } secs
194+ * @param {'UTC' | 'LOCAL' } tz
195+ * @returns {Date }
196+ */
197+ function get_tz_date ( hours , mins , secs , tz ) {
198+ const date = new Date ( ) ;
199+
200+ if ( tz === 'UTC' ) {
201+ date . setUTCHours ( hours ) ;
202+ date . setUTCMinutes ( hours ) ;
203+ date . setUTCSeconds ( secs ) ;
204+ date . setUTCMilliseconds ( 0 ) ;
205+ } else {
206+ date . setHours ( hours ) ;
207+ date . setMinutes ( mins ) ;
208+ date . setSeconds ( secs ) ;
209+ date . setMilliseconds ( 0 ) ;
210+ }
211+
212+ return date ;
213+ }
214+
137215/**
138216 * lock_and_run acquires a flock and calls the given callback after
139217 * acquiring the lock
0 commit comments