UNPKG

@applitools/eyes-storybook

Version:
152 lines (136 loc) 4.26 kB
'use strict'; function createPagePool({initPage, logger, freePageTimeout = 300_000}) { let counter = 0; const fullPageObjs = []; logger.log(`[page pool] created`); let currWaitOnFreePage = Promise.resolve(); const pagePool = { getFreePage, removeAndAddPage, createPage: async () => { const fullPageObj = await createPage(); fullPageObjs.push(fullPageObj); return toSmallPageObj(fullPageObj); }, addToPool: pageId => { const fullPageObj = fullPageObjs.find(p => p.pageId === pageId); if (fullPageObj) { fullPageObj.addToPool(); } }, removePage: pageId => { const fullPageObj = fullPageObjs.find(p => p.pageId === pageId); if (fullPageObj) { fullPageObj.removePage(); } }, isInPool: pageId => { const fullPageObj = fullPageObjs.find(p => p.pageId === pageId); return fullPageObj && fullPageObj.isInPool(); }, drain: async () => { // only call pagePool.drain if you KNOW all pages are free logger.log('[page pool] draining pool'); for (const {page, pageId} of [...fullPageObjs]) { await page.close(); await removeAndAddPage(pageId); } }, isClosed: false, }; return pagePool; async function removeAndAddPage(pageId) { pagePool.removePage(pageId); const {pageId: newPageId} = await pagePool.createPage(); pagePool.addToPool(newPageId); } async function getFreePage(tryCount = 0) { logger.log(`[page pool] waiting for free page, tryCount=${tryCount}`); await currWaitOnFreePage; const availablePages = fullPageObjs.filter(p => p.isInPool()); // wait up to 5 minutes if (availablePages.length === 0) { const INTERVAL = 500; if (tryCount < freePageTimeout / INTERVAL) { logger.log(`[page pool] no available pages, retrying to get free page...`); await new Promise(r => setTimeout(r, INTERVAL)); return getFreePage(tryCount + 1); } else { throw new Error('Could not find free page, timed out after waiting 5 minutes'); } } logger.log(`[page pool] waiting on pages ${availablePages.map(({pageId}) => pageId)}`); currWaitOnFreePage = Promise.race( availablePages.map(async p => { await p.waitUntilFree(); return p; }), ); const fullPageObj = await currWaitOnFreePage; if (fullPageObj.isInPool()) { fullPageObj.occupyPage(); logger.log(`[page pool] free page found: ${fullPageObj.pageId}`); return toSmallPageObj(fullPageObj); } else { logger.log(`[page pool] free page found, but it is no longer in pool: ${fullPageObj.pageId}`); return getFreePage(tryCount + 1); } } async function createPage() { const pageId = counter++; let workPromise = Promise.resolve(); let resolveWork; let isActive; let createdAt; const page = await initPage({pageId, pagePool}); return { page, pageId, markPageAsFree, waitUntilFree, occupyPage, removePage, isInPool, addToPool, getCreatedAt, }; function markPageAsFree() { logger.log('[page pool] marking page as free', pageId); resolveWork(); } async function waitUntilFree() { logger.log(`[page ${pageId}] waitUntilFree before`); await workPromise; logger.log(`[page ${pageId}] waitUntilFree after`); } function occupyPage() { workPromise = new Promise(resolve => { resolveWork = resolve; }); } function removePage() { logger.log(`[page ${pageId}] removePage`); fullPageObjs.splice( fullPageObjs.findIndex(p => p.pageId === pageId), 1, ); isActive = false; resolveWork && resolveWork(); } function isInPool() { return isActive; } function addToPool() { logger.log(`[page ${pageId}] addToPool`); isActive = true; createdAt = Date.now(); } function getCreatedAt() { return createdAt; } } function toSmallPageObj({page, pageId, markPageAsFree, removePage, getCreatedAt}) { return {page, pageId, markPageAsFree, removePage, getCreatedAt}; } } module.exports = createPagePool;