refactor: Change the applications caching logic
MODIFY
lib/basedriver/helpers.js
lib/basedriver/helpers.js
@@ -17,13 +17,51 @@ const ZIP_MIME_TYPES = [
'application/x-zip-compressed',
'multipart/x-zip',
];
+const CACHED_APPS_MAX_AGE = 1000 * 60 * 60 * 24;
const APPLICATIONS_CACHE = new LRU({
- max: 100,
+ maxAge: CACHED_APPS_MAX_AGE, // expire after 24 hours
+ updateAgeOnGet: true,
+ dispose: async (app, {fullPath}) => {
+ logger.info(`The application '${app}' cached at '${fullPath}' ` +
+ `has expired after ${CACHED_APPS_MAX_AGE}ms`);
+ if (await fs.exists(fullPath)) {
+ await fs.rimraf(fullPath);
+ }
+ },
+ noDisposeOnSet: true,
});
const APPLICATIONS_CACHE_GUARD = new AsyncLock();
const SANITIZE_REPLACEMENT = '-';
const DEFAULT_BASENAME = 'appium-app';
+
+async function cleanupCachedApps () {
+ if (!APPLICATIONS_CACHE.length) {
+ return;
+ }
+
+ logger.debug('Performing cleanup of the applications cache');
+ const cleanupPromises = [];
+ for (const {fullPath} of APPLICATIONS_CACHE.values()) {
+ cleanupPromises.push((async () => {
+ if (await fs.exists(fullPath)) {
+ await fs.rimraf(fullPath);
+ }
+ })());
+ }
+ try {
+ await B.all(cleanupPromises);
+ } catch (e) {
+ logger.error(e);
+ } finally {
+ APPLICATIONS_CACHE.reset();
+ }
+}
+
+process.on('exit', cleanupCachedApps);
+process.on('SIGINT', cleanupCachedApps);
+
+
async function retrieveHeaders (link) {
try {
const response = await asyncRequest({
@@ -192,6 +230,13 @@ async function configureApp (app, supportedAppExtensions) {
verifyAppExtension(newApp, supportedAppExtensions);
if (app !== newApp && (archiveHash || currentModified)) {
+ if (APPLICATIONS_CACHE.has(app)) {
+ const {fullPath} = APPLICATIONS_CACHE.get(app);
+ // Clean up the obsolete entry first if needed
+ if (fullPath !== newApp && await fs.exists(fullPath)) {
+ await fs.rimraf(fullPath);
+ }
+ }
APPLICATIONS_CACHE.set(app, {
hash: archiveHash,
lastModified: currentModified,

refactor: Change the applications caching logic (#374)