Skip to content

Commit 9939764

Browse files
authored
feat: better pool API (#77)
* feat: better pool API * test: update * docs: fix typo
1 parent c90afd7 commit 9939764

File tree

5 files changed

+81
-52
lines changed

5 files changed

+81
-52
lines changed

README.md

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -475,42 +475,48 @@ const browserless = require('browserless')
475475

476476
**browserless** uses internally a singleton browser instance.
477477

478-
You can use a pool instances using [`@browserless/pool`](https://github.com/Kikobeats/browserless/tree/master/packages/pool) package.
478+
If you want to keep multiple browsers open, you can use [`@browserless/pool`](https://github.com/Kikobeats/browserless/tree/master/packages/pool) package.
479479

480480
```js
481481
const createBrowserless = require('@browserless/pool')
482+
482483
const browserlessPool = createBrowserless({
483-
poolOpts: {
484-
max: 15,
485-
min: 2
486-
}
484+
max: 2, // max browsers to keep open
485+
timeout: 30000 // max time a browser is consiedered fresh
487486
})
488487
```
489488

490-
491-
The API is the same than `browserless`. now the constructor is accepting an extra option called `poolOpts`.
492-
493-
This setting is used for initializing the pool properly. You can see what you can specify there at [node-pool#opts](https://github.com/coopernurse/node-pool#createpool).
494-
495-
Also, you can interact with a standalone `browserless` instance of your pool.
489+
You can still pass specific puppeteer options as second argument:
496490

497491
```js
498-
const createBrowserless = require('browserless')
499-
const browserlessPool = createBrowserless.pool()
492+
const createBrowserless = require('@browserless/pool')
500493

501-
// get a browserless instance from the pool
502-
browserlessPool(async browserless => {
503-
// get a page from the browser instance
504-
const page = await browserless.page()
505-
await browserless.goto(page, { url: url.toString() })
506-
const html = await page.content()
507-
console.log(html)
508-
process.exit()
494+
const browserlessPool = createBrowserless({
495+
max: 2, // max browsers to keep open
496+
timeout: 30000 // max time a browser is consiedered fresh
497+
}, {
498+
ignoreHTTPSErrors: true,
499+
args: [
500+
'--disable-gpu',
501+
'--single-process',
502+
'--no-zygote',
503+
'--no-sandbox',
504+
'--hide-scrollbars'
505+
]
509506
})
510507
```
511508

509+
After that, the API is the same than **browserless**:
510+
511+
```js
512+
browserlessPool
513+
.screenshot('http://example.com', { device: 'iPhone 6' })
514+
.then(buffer => {
515+
console.log(`your screenshot is here!`)
516+
})
517+
```
512518

513-
You don't need to think about the acquire/release step: It's done automagically ✨.
519+
Every time you call the pool, it handles acquire and release a new browser instance from the pool ✨.
514520

515521
## Packages
516522

packages/pool/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"threads"
2525
],
2626
"dependencies": {
27+
"debug-logfmt": "~1.0.3",
2728
"generic-pool": "~3.7.1"
2829
},
2930
"devDependencies": {

packages/pool/src/create.js

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,59 @@
11
'use strict'
22

3+
const debug = require('debug-logfmt')('browserless:pool')
34
const createBrowserless = require('browserless')
45
const genericPool = require('generic-pool')
6+
const assert = require('assert')
57

6-
module.exports = (opts, launchOpts) => {
7-
const factory = {
8-
create: async () => ({
9-
...(await createBrowserless(launchOpts))
10-
}),
11-
destroy: browserless => browserless.browser.close()
12-
}
8+
const poolInfo = pool => ({
9+
size: pool.size,
10+
available: pool.available,
11+
borrowed: pool.borrowed,
12+
pending: pool.pending
13+
})
1314

14-
const pool = genericPool.createPool(factory, opts)
15+
const POOL_OPTS = {
16+
// should the pool start creating resources, initialize the evictor,
17+
// etc once the constructor is called.
18+
autostart: true,
19+
// minimum number of resources to keep in pool at any given time.
20+
// If this is set >= max, the pool will silently set the min to equal.
21+
min: 0,
22+
// Number of resources to check each eviction run
23+
testOnBorrow: true
24+
}
1525

16-
return async fn => {
17-
let error
18-
let result
19-
let browserless
26+
module.exports = (opts, launchOpts) => {
27+
assert(opts.timeout, 'opts.timeout is required')
28+
assert(opts.max, 'opts.max is required')
2029

21-
try {
22-
browserless = await pool.acquire()
23-
result = await fn(browserless)
24-
} catch (err) {
25-
error = err
30+
const factory = {
31+
create: () => {
32+
const browserless = createBrowserless(launchOpts)
33+
browserless.createdAt = Date.now()
34+
browserless.lifespan = () => Date.now() - browserless.createdAt
35+
debug('create', { createdAt: browserless.createdAt })
36+
return browserless
37+
},
38+
destroy: browserless => {
39+
debug('destroy', {
40+
createdAt: browserless.createdAt,
41+
lifespan: browserless.lifespan()
42+
})
43+
return browserless.destroy()
44+
},
45+
validate: browserless => {
46+
const lifespan = browserless.lifespan()
47+
const isValid = lifespan < opts.timeout
48+
debug('validate', { createdAt: browserless.createdAt, lifespan, isValid })
49+
return isValid
2650
}
51+
}
52+
53+
const pool = genericPool.createPool(factory, { ...POOL_OPTS, ...opts })
2754

28-
if (browserless) await pool.release(browserless)
29-
if (error) throw error
30-
return result
55+
return fn => {
56+
debug('acquire browser', poolInfo(pool))
57+
return pool.use(fn)
3158
}
3259
}

packages/pool/src/index.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,10 @@
22

33
const createPool = require('./create')
44

5-
const POOL_OPTS = {
6-
max: 15,
7-
min: 2
8-
}
9-
10-
module.exports = ({ opts, ...launchOpts } = {}) => {
11-
const poolOpts = { ...POOL_OPTS, ...opts }
12-
const pool = createPool(poolOpts, launchOpts)
5+
module.exports = (opts, launchOpts) => {
6+
const pool = createPool(opts, launchOpts)
137
;['html', 'text', 'pdf', 'screenshot'].forEach(key => {
14-
pool[key] = (url, opts) => pool(browserless => browserless[key](url, opts))
8+
pool[key] = (...args) => pool(browserless => browserless[key](...args))
159
})
1610
return pool
1711
}

packages/pool/test/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
require('@browserless/test')(require('../src'))
1+
const createPool = require('../src')
2+
require('@browserless/test')(() => createPool({ max: 2, timeout: 30000 }))

0 commit comments

Comments
 (0)