This repository has been archived by the owner on Apr 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpool.ts
141 lines (139 loc) · 4.36 KB
/
pool.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { Browser } from './browser';
import { debugLog } from './logging';
interface paramsType {
maxBrowsers: number,
maxPages: number,
maxHits: number,
maxAgeUnused: number,
executablePath: string,
maxQueueSize: number,
}
// Pool of browsers
export class Pool {
// id, browser
pool: Map<number, Browser>;
params: paramsType;
periodicTimer: NodeJS.Timeout;
constructor(
maxBrowsers: number,
maxPages: number,
maxHits: number,
maxAgeUnused: number,
executablePath: string,
maxQueueSize: number,
) {
this.pool = new Map<number, Browser>();
this.params = {
maxBrowsers,
maxPages,
maxHits,
maxAgeUnused,
executablePath,
maxQueueSize,
};
this.periodicTimer = this.periodicChecks();
}
periodicChecks() {
return setInterval(
() => {
debugLog.pool("periodic checks");
this.pool.forEach((b, id) => {
if (b.isUnused()) {
this.closeBrowser(id);
} else if (b.renewMe()) {
this.renewBrowser(id);
}
});
}, 10000
);
}
canAddBrowser() {
return this.pool.size < this.params.maxBrowsers;
}
newBrowserID() {
if (!this.canAddBrowser()) {
throw Error("cannot add a browser");
}
let nextID = 0;
while (nextID < Math.max(this.pool.size, 1)) {
if (!this.pool.has(nextID)) {
return nextID;
}
nextID++
}
nextID++; // equals to size of set
return nextID;
}
async addBrowser() {
debugLog.pool("adding browser");
if (!this.canAddBrowser()) {
throw Error("reached maximum number of browsers: " + this.params.maxBrowsers);
}
const id = this.newBrowserID();
const browser = new Browser(
this.params.executablePath,
this.params.maxPages,
this.params.maxHits,
this.params.maxAgeUnused,
this.params.maxQueueSize,
);
await browser.launched;
this.pool.set(id, browser);
debugLog.pool("added browser with ID " + id);
const test = this.pool.get(id);
return browser;
}
async closeBrowser(id: number) {
debugLog.pool("closing browser with ID " + id);
const browser = this.pool.get(id);
if (browser === undefined) {
throw Error("browser for id " + id + " does not exist");
}
await browser.close();
this.pool.delete(id);
}
async close() {
debugLog.pool("closing pool");
clearTimeout(this.periodicTimer);
for (const id of this.pool.keys()) {
await this.closeBrowser(id);
}
}
getBrowserLeastPages() {
let minID = 0, minPages = Infinity;
this.pool.forEach((b, id) => {
if (b.stats.pages < minPages) {
minPages = b.stats.pages;
minID = id;
}
});
const browser = this.pool.get(minID);
if (browser === undefined) {
throw Error("browser for id " + minID + " does not exist");
}
debugLog.pool("got browser with least pages, ID " + minID + ", pages: " + browser.stats.pages);
return browser;
}
// Gets the first browser which has not reached the
// maximum number of pages yet.
async getBrowser() {
debugLog.pool("getting a browser");
for (const browser of this.pool.values()) {
if (browser.stats.pages < this.params.maxPages) {
return browser;
}
}
// No browser or
// all browsers reached their maximum capacity of pages
if (this.canAddBrowser()) {
return await this.addBrowser();
}
// Max number of browsers so enqueue to the least busy browser
return this.getBrowserLeastPages();
}
async renewBrowser(id: number) {
debugLog.pool("renewing browser with ID " + id);
await this.closeBrowser(id);
await this.addBrowser();
}
}