fix(updateManager): Refine cache management for service worker updates.
This commit is contained in:
		| @@ -1,5 +1,12 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2025-02-03 - 3.0.57 - fix(updateManager) | ||||
| Refine cache management for service worker updates. | ||||
|  | ||||
| - Ensured cache is forcibly updated if older than defined maximum age. | ||||
| - Implemented interval checks and forced updates for cache staleness. | ||||
| - Updated version information and cache timestamps upon forced updates or validations. | ||||
|  | ||||
| ## 2025-02-03 - 3.0.56 - fix(cachemanager) | ||||
| Adjust cache control headers and fix redundant code | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@api.global/typedserver', | ||||
|   version: '3.0.56', | ||||
|   version: '3.0.57', | ||||
|   description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.' | ||||
| } | ||||
|   | ||||
| @@ -17,24 +17,42 @@ export class UpdateManager { | ||||
|   /** | ||||
|    * checks wether an update is needed | ||||
|    */ | ||||
|   private readonly MAX_CACHE_AGE = 24 * 60 * 60 * 1000; // 24 hours in milliseconds | ||||
|   private readonly MIN_CHECK_INTERVAL = 100000; // 100 seconds in milliseconds | ||||
|   private lastCacheTimestamp: number = 0; | ||||
|  | ||||
|   public async checkUpdate(cacheManager: CacheManager): Promise<boolean> { | ||||
|     const lswVersionInfoKey = 'versionInfo'; | ||||
|     const cacheTimestampKey = 'cacheTimestamp'; | ||||
|  | ||||
|     // Initialize or load version info | ||||
|     if (!this.lastVersionInfo && !(await this.serviceworkerRef.store.check(lswVersionInfoKey))) { | ||||
|       this.lastVersionInfo = { | ||||
|         appHash: '', | ||||
|         appSemVer: 'v0.0.0', | ||||
|       }; | ||||
|     } else if ( | ||||
|       !this.lastVersionInfo && | ||||
|       (await this.serviceworkerRef.store.check(lswVersionInfoKey)) | ||||
|     ) { | ||||
|     } else if (!this.lastVersionInfo && (await this.serviceworkerRef.store.check(lswVersionInfoKey))) { | ||||
|       this.lastVersionInfo = await this.serviceworkerRef.store.get(lswVersionInfoKey); | ||||
|     } | ||||
|  | ||||
|     // Load or initialize cache timestamp | ||||
|     if (await this.serviceworkerRef.store.check(cacheTimestampKey)) { | ||||
|       this.lastCacheTimestamp = await this.serviceworkerRef.store.get(cacheTimestampKey); | ||||
|     } | ||||
|  | ||||
|     const now = Date.now(); | ||||
|     const millisSinceLastCheck = now - this.lastUpdateCheck; | ||||
|     if (millisSinceLastCheck < 100000) { | ||||
|       // TODO account for being offline | ||||
|     const cacheAge = now - this.lastCacheTimestamp; | ||||
|  | ||||
|     // Force update if cache is too old | ||||
|     if (cacheAge > this.MAX_CACHE_AGE) { | ||||
|       logger.log('info', `Cache is older than ${this.MAX_CACHE_AGE}ms, forcing update...`); | ||||
|       await this.forceUpdate(cacheManager); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     // Regular update check interval | ||||
|     if (millisSinceLastCheck < this.MIN_CHECK_INTERVAL && cacheAge < this.MAX_CACHE_AGE) { | ||||
|       return false; | ||||
|     } | ||||
|     logger.log('info', 'checking for update of the app by comparing app hashes...'); | ||||
| @@ -49,9 +67,17 @@ export class UpdateManager { | ||||
|       this.performAsyncUpdateDebouncedTask.trigger(); | ||||
|       this.lastVersionInfo = currentVersionInfo; | ||||
|       await this.serviceworkerRef.store.set(lswVersionInfoKey, this.lastVersionInfo); | ||||
|        | ||||
|       // Update cache timestamp | ||||
|       this.lastCacheTimestamp = now; | ||||
|       await this.serviceworkerRef.store.set('cacheTimestamp', now); | ||||
|     } else { | ||||
|       logger.log('ok', 'caches are still valid, performing revalidation in a bit...'); | ||||
|       this.performAsyncCacheRevalidationDebouncedTask.trigger(); | ||||
|        | ||||
|       // Update cache timestamp after successful revalidation | ||||
|       this.lastCacheTimestamp = now; | ||||
|       await this.serviceworkerRef.store.set('cacheTimestamp', now); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -70,6 +96,17 @@ export class UpdateManager { | ||||
|   /** | ||||
|    * this task is executed once we know that there is a new version available | ||||
|    */ | ||||
|   private async forceUpdate(cacheManager: CacheManager) { | ||||
|     logger.log('info', 'Forcing cache update due to staleness'); | ||||
|     await this.serviceworkerRef.cacheManager.cleanCaches('Cache is stale, forcing update.'); | ||||
|     const currentVersionInfo = await this.getVersionInfoFromServer(); | ||||
|     this.lastVersionInfo = currentVersionInfo; | ||||
|     await this.serviceworkerRef.store.set('versionInfo', this.lastVersionInfo); | ||||
|     this.lastCacheTimestamp = Date.now(); | ||||
|     await this.serviceworkerRef.store.set('cacheTimestamp', this.lastCacheTimestamp); | ||||
|     await this.serviceworkerRef.leleServiceWorkerBackend.triggerReloadAll(); | ||||
|   } | ||||
|  | ||||
|   public performAsyncUpdateDebouncedTask = new plugins.taskbuffer.TaskDebounced({ | ||||
|     name: 'performAsyncUpdate', | ||||
|     taskFunction: async () => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user