blob: 9f094bb347634c82b277bee2013a053e012d7d67 [file] [log] [blame]
/**
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the License for the specific language governing permissions and limitations under
the License.
**/
import puppeteer, { Page, Browser } from 'puppeteer';
import { RunnableTask } from './runnableTask';
/** Pool of browsers that can be used to run tasks in parallel */
export class BrowserPool {
private instances: number;
private headless: boolean;
private initPage: (page: Page) => Promise<any>;
private pool: Browser[];
private queue: RunnableTask[] = [];
/**
* Create a new BrowserPool
*
* @param instances number of browsers to create
* @param headless whether to run the browsers in headless mode
* @param initPage function to run on each page before running a task
* @returns a new BrowserPool
*/
constructor(
instances: number,
headless: boolean = true,
initPage?: (page: Page) => Promise<any>,
) {
this.instances = instances;
this.headless = headless;
this.pool = [];
this.initPage = initPage || (async (page: Page) => {});
}
/** Initialize the browser pool */
public async init() {
for (let i = 0; i < this.instances; i++) {
const browser = await puppeteer.launch({
headless: this.headless ? 'new' : false,
args: ['--enable-webgl', '--no-sandbox', '--disable-web-security'],
});
const [page] = await browser.pages();
await this.initPage(page);
this.pool.push(browser);
}
}
/**
* Queue a task to be run
*
* @param task task to run
*/
public async queueTask(task: RunnableTask) {
this.queue.push(task);
}
/** Run all queued tasks in parallel */
public async run() {
const results = [];
// run the queue in parallel with only one browser per task at max
while (this.queue.length) {
const res = await Promise.all(
this.queue.splice(0, this.instances).map(async (task, index) => {
const browser = this.pool[index];
const [page] = await browser.pages();
return await task.run(page);
}),
);
results.push(...res);
}
return results;
}
/** Close all browsers in the pool */
public async close() {
await Promise.all(this.pool.map((browser) => browser.close()));
}
}