@browserless.io/browserless 2.4.0 → 2.5.0-beta-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/bin/browserless.js +17 -127
- package/bin/scaffold/README.md +95 -14
- package/build/browserless.d.ts +5 -3
- package/build/browserless.js +10 -6
- package/build/browsers/index.d.ts +5 -3
- package/build/browsers/index.js +6 -4
- package/build/data/selectors.json +1 -1
- package/build/exports.d.ts +1 -0
- package/build/exports.js +1 -0
- package/build/file-system.d.ts +2 -3
- package/build/file-system.js +10 -21
- package/build/file-system.spec.js +35 -18
- package/build/hooks.d.ts +18 -4
- package/build/hooks.js +33 -4
- package/build/limiter.d.ts +3 -2
- package/build/limiter.js +5 -3
- package/build/limiter.spec.js +45 -26
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/management/http/metrics-total.get.js +1 -1
- package/build/routes/management/http/metrics.get.js +2 -2
- package/build/sdk-utils.d.ts +13 -0
- package/build/sdk-utils.js +94 -0
- package/build/server.d.ts +3 -2
- package/build/server.js +6 -4
- package/build/types.d.ts +2 -2
- package/build/utils.js +6 -10
- package/external/after.js +1 -1
- package/external/before.js +1 -1
- package/external/browser.js +1 -1
- package/external/page.js +1 -1
- package/package.json +7 -7
- package/src/browserless.ts +21 -3
- package/src/browsers/index.ts +9 -6
- package/src/exports.ts +1 -0
- package/src/file-system.spec.ts +43 -18
- package/src/file-system.ts +16 -30
- package/src/hooks.ts +46 -4
- package/src/limiter.spec.ts +82 -112
- package/src/limiter.ts +3 -3
- package/src/routes/management/http/metrics-total.get.ts +3 -3
- package/src/routes/management/http/metrics.get.ts +2 -2
- package/src/sdk-utils.ts +136 -0
- package/src/server.ts +4 -3
- package/src/shared/content.http.ts +0 -1
- package/src/types.ts +2 -2
- package/src/utils.ts +10 -11
- package/static/docs/swagger.json +11 -11
- package/static/docs/swagger.min.json +10 -10
- package/static/function/client.js +76 -63
package/build/exports.d.ts
CHANGED
package/build/exports.js
CHANGED
package/build/file-system.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export declare class FileSystem extends EventEmitter {
|
|
|
9
9
|
protected currentAESKey: Buffer;
|
|
10
10
|
protected log: import("debug").Debugger;
|
|
11
11
|
constructor(config: Config);
|
|
12
|
-
private handleTokenChange;
|
|
13
12
|
/**
|
|
14
13
|
* Appends contents to a file-path for persistance. File contents are
|
|
15
14
|
* encrypted before being saved to disk. Reads happen via the in-memory
|
|
@@ -19,7 +18,7 @@ export declare class FileSystem extends EventEmitter {
|
|
|
19
18
|
* @param newContent A string of new content to add to the file
|
|
20
19
|
* @returns void
|
|
21
20
|
*/
|
|
22
|
-
append: (path: string, newContent: string) => Promise<void>;
|
|
21
|
+
append: (path: string, newContent: string, shouldEncode: boolean) => Promise<void>;
|
|
23
22
|
/**
|
|
24
23
|
* Reads contents from the local map, if any exist, or loads
|
|
25
24
|
* from the file system and hydrates the cache for the particular filepath
|
|
@@ -27,7 +26,7 @@ export declare class FileSystem extends EventEmitter {
|
|
|
27
26
|
* @param path The filepath of the contents to read
|
|
28
27
|
* @returns Promise of the contents separated by newlines
|
|
29
28
|
*/
|
|
30
|
-
read: (path: string) => Promise<string[]>;
|
|
29
|
+
read: (path: string, encoded: boolean) => Promise<string[]>;
|
|
31
30
|
/**
|
|
32
31
|
* Implement any browserless-core-specific shutdown logic here.
|
|
33
32
|
* Calls the empty-SDK stop method for downstream implementations.
|
package/build/file-system.js
CHANGED
|
@@ -10,21 +10,7 @@ export class FileSystem extends EventEmitter {
|
|
|
10
10
|
super();
|
|
11
11
|
this.config = config;
|
|
12
12
|
this.currentAESKey = config.getAESKey();
|
|
13
|
-
this.config.on('token', this.handleTokenChange);
|
|
14
13
|
}
|
|
15
|
-
handleTokenChange = async () => {
|
|
16
|
-
this.log(`Token has changed, updating file-system contents`);
|
|
17
|
-
const start = Date.now();
|
|
18
|
-
const newAESKey = this.config.getAESKey();
|
|
19
|
-
await Promise.all(Array.from(this.fsMap).map(async ([filePath, contents]) => {
|
|
20
|
-
const newlyEncoded = encrypt(contents.join('\n'), Buffer.from(newAESKey));
|
|
21
|
-
return writeFile(filePath, newlyEncoded);
|
|
22
|
-
})).catch((e) => {
|
|
23
|
-
this.log(`Error in setting new token: "${e}"`);
|
|
24
|
-
});
|
|
25
|
-
this.log(`Successfully updated file encodings in ${Date.now() - start}ms`);
|
|
26
|
-
this.currentAESKey = this.config.getAESKey();
|
|
27
|
-
};
|
|
28
14
|
/**
|
|
29
15
|
* Appends contents to a file-path for persistance. File contents are
|
|
30
16
|
* encrypted before being saved to disk. Reads happen via the in-memory
|
|
@@ -34,11 +20,13 @@ export class FileSystem extends EventEmitter {
|
|
|
34
20
|
* @param newContent A string of new content to add to the file
|
|
35
21
|
* @returns void
|
|
36
22
|
*/
|
|
37
|
-
append = async (path, newContent) => {
|
|
38
|
-
const contents = await this.read(path);
|
|
23
|
+
append = async (path, newContent, shouldEncode) => {
|
|
24
|
+
const contents = await this.read(path, shouldEncode);
|
|
39
25
|
contents.push(newContent);
|
|
40
26
|
this.fsMap.set(path, contents);
|
|
41
|
-
const encoded =
|
|
27
|
+
const encoded = shouldEncode
|
|
28
|
+
? await encrypt(contents.join('\n'), this.currentAESKey)
|
|
29
|
+
: contents.join('\n');
|
|
42
30
|
return writeFile(path, encoded.toString());
|
|
43
31
|
};
|
|
44
32
|
/**
|
|
@@ -48,15 +36,16 @@ export class FileSystem extends EventEmitter {
|
|
|
48
36
|
* @param path The filepath of the contents to read
|
|
49
37
|
* @returns Promise of the contents separated by newlines
|
|
50
38
|
*/
|
|
51
|
-
read = async (path) => {
|
|
39
|
+
read = async (path, encoded) => {
|
|
52
40
|
const hasKey = this.fsMap.has(path);
|
|
53
41
|
if (hasKey) {
|
|
54
42
|
return this.fsMap.get(path);
|
|
55
43
|
}
|
|
56
44
|
const contents = (await readFile(path).catch(() => '')).toString();
|
|
57
|
-
const
|
|
58
|
-
?
|
|
59
|
-
:
|
|
45
|
+
const decoded = encoded && contents.length
|
|
46
|
+
? await decrypt(contents, this.currentAESKey)
|
|
47
|
+
: contents;
|
|
48
|
+
const splitContents = decoded.length ? decoded.split('\n') : [];
|
|
60
49
|
this.fsMap.set(path, splitContents);
|
|
61
50
|
return splitContents;
|
|
62
51
|
};
|
|
@@ -1,44 +1,61 @@
|
|
|
1
|
-
import { Config, FileSystem,
|
|
1
|
+
import { Config, FileSystem, noop } from '@browserless.io/browserless';
|
|
2
2
|
import { readFile, unlink } from 'fs/promises';
|
|
3
3
|
import { expect } from 'chai';
|
|
4
4
|
const filePath = '/tmp/_browserless_test_fs_';
|
|
5
5
|
describe('File-System', () => {
|
|
6
|
-
afterEach(async () => unlink(filePath));
|
|
6
|
+
afterEach(async () => unlink(filePath).catch(noop));
|
|
7
7
|
it('saves and encodes files', async () => {
|
|
8
8
|
const mySecretContents = 'pony-foo';
|
|
9
9
|
const config = new Config();
|
|
10
10
|
config.setToken('browserless.io');
|
|
11
11
|
const f = new FileSystem(config);
|
|
12
|
-
await f.append(filePath, mySecretContents);
|
|
13
|
-
expect(await f.read(filePath)).to.eql([mySecretContents]);
|
|
12
|
+
await f.append(filePath, mySecretContents, true);
|
|
13
|
+
expect(await f.read(filePath, true)).to.eql([mySecretContents]);
|
|
14
14
|
const rawText = (await readFile(filePath)).toString();
|
|
15
15
|
expect(rawText.toString()).to.not.include(mySecretContents);
|
|
16
16
|
});
|
|
17
|
-
it('
|
|
17
|
+
it('saves files without encoding', async () => {
|
|
18
|
+
const mySecretContents = 'pony-foo';
|
|
19
|
+
const config = new Config();
|
|
20
|
+
config.setToken('browserless.io');
|
|
21
|
+
const f = new FileSystem(config);
|
|
22
|
+
await f.append(filePath, mySecretContents, false);
|
|
23
|
+
expect(await f.read(filePath, false)).to.eql([mySecretContents]);
|
|
24
|
+
const rawText = (await readFile(filePath)).toString();
|
|
25
|
+
expect(rawText.toString()).to.include(mySecretContents);
|
|
26
|
+
});
|
|
27
|
+
it('appends newlines to files and encodes them', async () => {
|
|
18
28
|
const mySecretContents = 'pony-foo';
|
|
19
29
|
const moreSecretContents = 'pony-pony-foo-foo';
|
|
20
30
|
const config = new Config();
|
|
21
31
|
config.setToken('browserless.io');
|
|
22
32
|
const f = new FileSystem(config);
|
|
23
|
-
await f.append(filePath, mySecretContents);
|
|
24
|
-
expect(await f.read(filePath)).to.eql([mySecretContents]);
|
|
25
|
-
await f.append(filePath, moreSecretContents);
|
|
26
|
-
expect(await f.read(filePath)).to.eql([
|
|
33
|
+
await f.append(filePath, mySecretContents, true);
|
|
34
|
+
expect(await f.read(filePath, true)).to.eql([mySecretContents]);
|
|
35
|
+
await f.append(filePath, moreSecretContents, true);
|
|
36
|
+
expect(await f.read(filePath, true)).to.eql([
|
|
27
37
|
mySecretContents,
|
|
28
38
|
moreSecretContents,
|
|
29
39
|
]);
|
|
40
|
+
const rawText = (await readFile(filePath)).toString();
|
|
41
|
+
expect(rawText).to.not.include(mySecretContents);
|
|
42
|
+
expect(rawText).to.not.include(moreSecretContents);
|
|
30
43
|
});
|
|
31
|
-
it('
|
|
44
|
+
it('appends newlines to files and does not encode them', async () => {
|
|
45
|
+
const mySecretContents = 'pony-foo';
|
|
46
|
+
const moreSecretContents = 'pony-pony-foo-foo';
|
|
32
47
|
const config = new Config();
|
|
33
48
|
config.setToken('browserless.io');
|
|
34
49
|
const f = new FileSystem(config);
|
|
35
|
-
|
|
36
|
-
await f.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
await f.append(filePath, mySecretContents, false);
|
|
51
|
+
expect(await f.read(filePath, false)).to.eql([mySecretContents]);
|
|
52
|
+
await f.append(filePath, moreSecretContents, false);
|
|
53
|
+
expect(await f.read(filePath, false)).to.eql([
|
|
54
|
+
mySecretContents,
|
|
55
|
+
moreSecretContents,
|
|
56
|
+
]);
|
|
57
|
+
const rawText = (await readFile(filePath)).toString();
|
|
58
|
+
expect(rawText).to.include(mySecretContents);
|
|
59
|
+
expect(rawText).to.include(moreSecretContents);
|
|
43
60
|
});
|
|
44
61
|
});
|
package/build/hooks.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { AfterResponse, BeforeRequest, BrowserHook, PageHook } from '@browserless.io/browserless';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
export declare class Hooks extends EventEmitter {
|
|
5
|
+
before(args: BeforeRequest): Promise<boolean>;
|
|
6
|
+
after(args: AfterResponse): Promise<unknown>;
|
|
7
|
+
page(args: PageHook): Promise<unknown>;
|
|
8
|
+
browser(args: BrowserHook): Promise<unknown>;
|
|
9
|
+
/**
|
|
10
|
+
* Implement any browserless-core-specific shutdown logic here.
|
|
11
|
+
* Calls the empty-SDK stop method for downstream implementations.
|
|
12
|
+
*/
|
|
13
|
+
shutdown: () => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Left blank for downstream SDK modules to optionally implement.
|
|
16
|
+
*/
|
|
17
|
+
stop: () => void;
|
|
18
|
+
}
|
package/build/hooks.js
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
// KEPT for backwards compatibility reasons since some downstream
|
|
3
|
+
// docker images will override these files to inject their own hook
|
|
4
|
+
// behaviors
|
|
1
5
|
// @ts-ignore
|
|
2
|
-
|
|
6
|
+
import { default as afterRequest } from '../external/after.js';
|
|
3
7
|
// @ts-ignore
|
|
4
|
-
|
|
8
|
+
import { default as beforeRequest } from '../external/before.js';
|
|
5
9
|
// @ts-ignore
|
|
6
|
-
|
|
10
|
+
import { default as browserHook } from '../external/browser.js';
|
|
7
11
|
// @ts-ignore
|
|
8
|
-
|
|
12
|
+
import { default as pageHook } from '../external/page.js';
|
|
13
|
+
export class Hooks extends EventEmitter {
|
|
14
|
+
before(args) {
|
|
15
|
+
return beforeRequest(args);
|
|
16
|
+
}
|
|
17
|
+
after(args) {
|
|
18
|
+
return afterRequest(args);
|
|
19
|
+
}
|
|
20
|
+
page(args) {
|
|
21
|
+
return pageHook(args);
|
|
22
|
+
}
|
|
23
|
+
browser(args) {
|
|
24
|
+
return browserHook(args);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Implement any browserless-core-specific shutdown logic here.
|
|
28
|
+
* Calls the empty-SDK stop method for downstream implementations.
|
|
29
|
+
*/
|
|
30
|
+
shutdown = async () => {
|
|
31
|
+
await this.stop();
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Left blank for downstream SDK modules to optionally implement.
|
|
35
|
+
*/
|
|
36
|
+
stop = () => { };
|
|
37
|
+
}
|
package/build/limiter.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="debug" />
|
|
2
|
-
import { AfterResponse, Config, Metrics, Monitoring, WebHooks } from '@browserless.io/browserless';
|
|
2
|
+
import { AfterResponse, Config, Hooks, Metrics, Monitoring, WebHooks } from '@browserless.io/browserless';
|
|
3
3
|
import q from 'queue';
|
|
4
4
|
export type LimitFn<TArgs extends unknown[], TResult> = (...args: TArgs) => Promise<TResult>;
|
|
5
5
|
export type ErrorFn<TArgs extends unknown[]> = (...args: TArgs) => void;
|
|
@@ -15,9 +15,10 @@ export declare class Limiter extends q {
|
|
|
15
15
|
protected metrics: Metrics;
|
|
16
16
|
protected monitor: Monitoring;
|
|
17
17
|
protected webhooks: WebHooks;
|
|
18
|
+
protected hooks: Hooks;
|
|
18
19
|
protected queued: number;
|
|
19
20
|
protected debug: import("debug").Debugger;
|
|
20
|
-
constructor(config: Config, metrics: Metrics, monitor: Monitoring, webhooks: WebHooks);
|
|
21
|
+
constructor(config: Config, metrics: Metrics, monitor: Monitoring, webhooks: WebHooks, hooks: Hooks);
|
|
21
22
|
protected handleEnd(): void;
|
|
22
23
|
protected jobEnd(jobInfo: AfterResponse): void;
|
|
23
24
|
protected handleSuccess({ detail: { job } }: {
|
package/build/limiter.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { TooManyRequests,
|
|
1
|
+
import { TooManyRequests, createLogger, } from '@browserless.io/browserless';
|
|
2
2
|
import q from 'queue';
|
|
3
3
|
export class Limiter extends q {
|
|
4
4
|
config;
|
|
5
5
|
metrics;
|
|
6
6
|
monitor;
|
|
7
7
|
webhooks;
|
|
8
|
+
hooks;
|
|
8
9
|
queued;
|
|
9
10
|
debug = createLogger('limiter');
|
|
10
|
-
constructor(config, metrics, monitor, webhooks) {
|
|
11
|
+
constructor(config, metrics, monitor, webhooks, hooks) {
|
|
11
12
|
super({
|
|
12
13
|
autostart: true,
|
|
13
14
|
concurrency: config.getConcurrent(),
|
|
@@ -17,6 +18,7 @@ export class Limiter extends q {
|
|
|
17
18
|
this.metrics = metrics;
|
|
18
19
|
this.monitor = monitor;
|
|
19
20
|
this.webhooks = webhooks;
|
|
21
|
+
this.hooks = hooks;
|
|
20
22
|
this.queued = config.getQueued();
|
|
21
23
|
this.debug(`Concurrency: ${this.concurrency} queue: ${this.queued} timeout: ${this.timeout}ms`);
|
|
22
24
|
config.on('concurrent', (concurrency) => {
|
|
@@ -43,7 +45,7 @@ export class Limiter extends q {
|
|
|
43
45
|
this.logQueue('All jobs complete.');
|
|
44
46
|
}
|
|
45
47
|
jobEnd(jobInfo) {
|
|
46
|
-
|
|
48
|
+
this.hooks.after(jobInfo);
|
|
47
49
|
}
|
|
48
50
|
handleSuccess({ detail: { job } }) {
|
|
49
51
|
const timeUsed = Date.now() - job.start;
|
package/build/limiter.spec.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import { Config, Limiter, Metrics, Monitoring, sleep, } from '@browserless.io/browserless';
|
|
1
|
+
import { Config, Hooks, Limiter, Metrics, Monitoring, WebHooks, sleep, } from '@browserless.io/browserless';
|
|
2
|
+
import Sinon, { spy } from 'sinon';
|
|
2
3
|
import { expect } from 'chai';
|
|
3
|
-
import { spy } from 'sinon';
|
|
4
4
|
const asyncNoop = () => Promise.resolve(undefined);
|
|
5
5
|
const noop = () => undefined;
|
|
6
|
-
const webHooks =
|
|
7
|
-
|
|
8
|
-
callFailedHealthURL: spy(),
|
|
9
|
-
callQueueAlertURL: spy(),
|
|
10
|
-
callRejectAlertURL: spy(),
|
|
11
|
-
callTimeoutAlertURL: spy(),
|
|
12
|
-
};
|
|
6
|
+
const webHooks = Sinon.createStubInstance(WebHooks);
|
|
7
|
+
const hooks = Sinon.createStubInstance(Hooks);
|
|
13
8
|
describe(`Limiter`, () => {
|
|
14
9
|
afterEach(() => {
|
|
15
10
|
webHooks.callFailedHealthURL.resetHistory();
|
|
@@ -17,8 +12,12 @@ describe(`Limiter`, () => {
|
|
|
17
12
|
webHooks.callRejectAlertURL.resetHistory();
|
|
18
13
|
webHooks.callTimeoutAlertURL.resetHistory();
|
|
19
14
|
webHooks.callErrorAlertURL.resetHistory();
|
|
15
|
+
hooks.before.resetHistory();
|
|
16
|
+
hooks.after.resetHistory();
|
|
17
|
+
hooks.browser.resetHistory();
|
|
18
|
+
hooks.page.resetHistory();
|
|
20
19
|
});
|
|
21
|
-
it('limits and queues function calls and calls queue alert urls', async () => {
|
|
20
|
+
it('limits and queues function calls, calls hooks, and calls queue alert urls', async () => {
|
|
22
21
|
return new Promise((resolve, reject) => {
|
|
23
22
|
const config = new Config();
|
|
24
23
|
config.setQueueAlertURL('https://example.com');
|
|
@@ -27,7 +26,7 @@ describe(`Limiter`, () => {
|
|
|
27
26
|
config.setConcurrent(1);
|
|
28
27
|
config.setQueued(1);
|
|
29
28
|
config.setTimeout(-1);
|
|
30
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
29
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
31
30
|
const handler = spy();
|
|
32
31
|
const job = limiter.limit(handler, asyncNoop, asyncNoop, noop);
|
|
33
32
|
job();
|
|
@@ -35,6 +34,7 @@ describe(`Limiter`, () => {
|
|
|
35
34
|
expect(handler.calledOnce).to.be.true;
|
|
36
35
|
limiter.addEventListener('end', () => {
|
|
37
36
|
try {
|
|
37
|
+
expect(hooks.after.called).to.be.true;
|
|
38
38
|
expect(handler.calledTwice).to.be.true;
|
|
39
39
|
expect(webHooks.callQueueAlertURL.calledOnce).to.be.true;
|
|
40
40
|
expect(metrics.get().queued).to.equal(1);
|
|
@@ -48,7 +48,7 @@ describe(`Limiter`, () => {
|
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
}).timeout(5000);
|
|
51
|
-
it('passes through arguments', () => {
|
|
51
|
+
it('passes through arguments', () => new Promise((resolve, reject) => {
|
|
52
52
|
const args = ['one', 'two', 'three'];
|
|
53
53
|
const config = new Config();
|
|
54
54
|
const metrics = new Metrics();
|
|
@@ -56,13 +56,23 @@ describe(`Limiter`, () => {
|
|
|
56
56
|
config.setConcurrent(1);
|
|
57
57
|
config.setQueued(0);
|
|
58
58
|
config.setTimeout(-1);
|
|
59
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
59
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
60
60
|
const handler = spy();
|
|
61
61
|
const job = limiter.limit(handler, asyncNoop, asyncNoop, noop);
|
|
62
62
|
// @ts-ignore will fix later
|
|
63
63
|
job(...args);
|
|
64
64
|
expect(handler.args[0]).to.eql(args);
|
|
65
|
-
|
|
65
|
+
limiter.addEventListener('end', () => {
|
|
66
|
+
try {
|
|
67
|
+
expect(hooks.after.args[0][0]).to.have.property('start');
|
|
68
|
+
expect(hooks.after.args[0][0]).to.have.property('status', 'successful');
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return reject(e);
|
|
72
|
+
}
|
|
73
|
+
resolve(undefined);
|
|
74
|
+
});
|
|
75
|
+
}));
|
|
66
76
|
it('waits to run jobs until the first are done', async () => {
|
|
67
77
|
const config = new Config();
|
|
68
78
|
const monitoring = new Monitoring(config);
|
|
@@ -70,7 +80,7 @@ describe(`Limiter`, () => {
|
|
|
70
80
|
config.setConcurrent(1);
|
|
71
81
|
config.setQueued(1);
|
|
72
82
|
config.setTimeout(-1);
|
|
73
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
83
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
74
84
|
const handlerOne = () => new Promise((r) => setTimeout(r, 50));
|
|
75
85
|
const handlerTwo = spy();
|
|
76
86
|
const jobOne = limiter.limit(handlerOne, asyncNoop, asyncNoop, noop);
|
|
@@ -89,7 +99,7 @@ describe(`Limiter`, () => {
|
|
|
89
99
|
config.setConcurrent(1);
|
|
90
100
|
config.setQueued(1);
|
|
91
101
|
config.setTimeout(-1);
|
|
92
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
102
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
93
103
|
const spy = () => new Promise((_r, rej) => rej(error));
|
|
94
104
|
const job = limiter.limit(spy, asyncNoop, asyncNoop, noop);
|
|
95
105
|
await job().catch(noop);
|
|
@@ -101,6 +111,7 @@ describe(`Limiter`, () => {
|
|
|
101
111
|
expect(metrics.get().error).to.eql(1);
|
|
102
112
|
expect(webHooks.callErrorAlertURL.getCalls()[0].firstArg).to.include(error);
|
|
103
113
|
expect(webHooks.callErrorAlertURL.calledOnce).to.be.true;
|
|
114
|
+
expect(hooks.after.args[0][0]).to.have.property('status', 'error');
|
|
104
115
|
});
|
|
105
116
|
});
|
|
106
117
|
});
|
|
@@ -112,7 +123,7 @@ describe(`Limiter`, () => {
|
|
|
112
123
|
config.setConcurrent(1);
|
|
113
124
|
config.setQueued(0);
|
|
114
125
|
config.setTimeout(-1);
|
|
115
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
126
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
116
127
|
const handler = spy();
|
|
117
128
|
const onError = spy();
|
|
118
129
|
const job = limiter.limit(handler, onError, noop, noop);
|
|
@@ -124,7 +135,7 @@ describe(`Limiter`, () => {
|
|
|
124
135
|
expect(onError.calledOnce).to.be.true;
|
|
125
136
|
expect(onError.args[0]).to.eql(args);
|
|
126
137
|
});
|
|
127
|
-
it('calls a timeout handler with arguments if a job takes too long', (
|
|
138
|
+
it('calls a timeout handler with arguments if a job takes too long', () => new Promise((resolve, reject) => {
|
|
128
139
|
const args = ['one', 'two', 'three'];
|
|
129
140
|
const config = new Config();
|
|
130
141
|
const metrics = new Metrics();
|
|
@@ -133,18 +144,26 @@ describe(`Limiter`, () => {
|
|
|
133
144
|
config.setQueued(0);
|
|
134
145
|
config.setTimeout(10);
|
|
135
146
|
let timer;
|
|
136
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
147
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
137
148
|
const handler = () => new Promise((d) => (timer = global.setTimeout(d, 1000)));
|
|
138
149
|
const onTimeout = (...calledArgs) => {
|
|
139
150
|
clearTimeout(timer);
|
|
140
151
|
expect(calledArgs).to.eql(args);
|
|
141
152
|
expect(webHooks.callTimeoutAlertURL.calledOnce).to.be.true;
|
|
142
|
-
r(null);
|
|
143
153
|
};
|
|
144
154
|
const job = limiter.limit(handler, noop, onTimeout, noop);
|
|
145
155
|
// @ts-ignore
|
|
146
156
|
job(...args);
|
|
147
|
-
|
|
157
|
+
limiter.addEventListener('end', () => {
|
|
158
|
+
try {
|
|
159
|
+
expect(hooks.after.args[0][0]).to.have.property('status', 'timedout');
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
return reject(e);
|
|
163
|
+
}
|
|
164
|
+
resolve(undefined);
|
|
165
|
+
});
|
|
166
|
+
}));
|
|
148
167
|
it('allows overriding the timeouts', async () => {
|
|
149
168
|
const config = new Config();
|
|
150
169
|
const metrics = new Metrics();
|
|
@@ -152,7 +171,7 @@ describe(`Limiter`, () => {
|
|
|
152
171
|
config.setConcurrent(2);
|
|
153
172
|
config.setQueued(0);
|
|
154
173
|
config.setTimeout(1);
|
|
155
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
174
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
156
175
|
const onTimeout = spy();
|
|
157
176
|
const handler = async () => new Promise((r) => setTimeout(r, 10));
|
|
158
177
|
const job = limiter.limit(handler, noop, onTimeout, noop);
|
|
@@ -169,7 +188,7 @@ describe(`Limiter`, () => {
|
|
|
169
188
|
config.setConcurrent(1);
|
|
170
189
|
config.setQueued(0);
|
|
171
190
|
config.setTimeout(20);
|
|
172
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
191
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
173
192
|
const handler = () => new Promise((r) => setTimeout(r, 1));
|
|
174
193
|
const timeout = spy();
|
|
175
194
|
const job = limiter.limit(handler, noop, timeout, noop);
|
|
@@ -184,7 +203,7 @@ describe(`Limiter`, () => {
|
|
|
184
203
|
config.setConcurrent(1);
|
|
185
204
|
config.setQueued(0);
|
|
186
205
|
config.setTimeout(-1);
|
|
187
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
206
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
188
207
|
const handler = spy();
|
|
189
208
|
const job = limiter.limit(handler, noop, noop, noop);
|
|
190
209
|
job();
|
|
@@ -207,7 +226,7 @@ describe(`Limiter`, () => {
|
|
|
207
226
|
config.setConcurrent(10);
|
|
208
227
|
config.setQueued(10);
|
|
209
228
|
config.setTimeout(-1);
|
|
210
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
229
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
211
230
|
const handler = spy();
|
|
212
231
|
const job = limiter.limit(handler, noop, noop, noop);
|
|
213
232
|
job().catch(() => {
|
|
@@ -227,7 +246,7 @@ describe(`Limiter`, () => {
|
|
|
227
246
|
config.setConcurrent(10);
|
|
228
247
|
config.setQueued(10);
|
|
229
248
|
config.setTimeout(-1);
|
|
230
|
-
const limiter = new Limiter(config, metrics, monitoring, webHooks);
|
|
249
|
+
const limiter = new Limiter(config, metrics, monitoring, webHooks, hooks);
|
|
231
250
|
const handler = spy();
|
|
232
251
|
const job = limiter.limit(handler, noop, noop, noop);
|
|
233
252
|
job();
|
|
@@ -394,14 +394,14 @@
|
|
|
394
394
|
"length": {
|
|
395
395
|
"type": "number"
|
|
396
396
|
},
|
|
397
|
-
"__@toStringTag@
|
|
397
|
+
"__@toStringTag@10918": {
|
|
398
398
|
"type": "string",
|
|
399
399
|
"const": "Uint8Array"
|
|
400
400
|
}
|
|
401
401
|
},
|
|
402
402
|
"required": [
|
|
403
403
|
"BYTES_PER_ELEMENT",
|
|
404
|
-
"__@toStringTag@
|
|
404
|
+
"__@toStringTag@10918",
|
|
405
405
|
"buffer",
|
|
406
406
|
"byteLength",
|
|
407
407
|
"byteOffset",
|
|
@@ -436,13 +436,13 @@
|
|
|
436
436
|
"byteLength": {
|
|
437
437
|
"type": "number"
|
|
438
438
|
},
|
|
439
|
-
"__@toStringTag@
|
|
439
|
+
"__@toStringTag@10918": {
|
|
440
440
|
"type": "string"
|
|
441
441
|
}
|
|
442
442
|
},
|
|
443
443
|
"additionalProperties": false,
|
|
444
444
|
"required": [
|
|
445
|
-
"__@toStringTag@
|
|
445
|
+
"__@toStringTag@10918",
|
|
446
446
|
"byteLength"
|
|
447
447
|
]
|
|
448
448
|
},
|
|
@@ -452,18 +452,18 @@
|
|
|
452
452
|
"byteLength": {
|
|
453
453
|
"type": "number"
|
|
454
454
|
},
|
|
455
|
-
"__@species@
|
|
455
|
+
"__@species@11019": {
|
|
456
456
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
457
457
|
},
|
|
458
|
-
"__@toStringTag@
|
|
458
|
+
"__@toStringTag@10918": {
|
|
459
459
|
"type": "string",
|
|
460
460
|
"const": "SharedArrayBuffer"
|
|
461
461
|
}
|
|
462
462
|
},
|
|
463
463
|
"additionalProperties": false,
|
|
464
464
|
"required": [
|
|
465
|
-
"__@species@
|
|
466
|
-
"__@toStringTag@
|
|
465
|
+
"__@species@11019",
|
|
466
|
+
"__@toStringTag@10918",
|
|
467
467
|
"byteLength"
|
|
468
468
|
]
|
|
469
469
|
},
|
|
@@ -535,14 +535,14 @@
|
|
|
535
535
|
"length": {
|
|
536
536
|
"type": "number"
|
|
537
537
|
},
|
|
538
|
-
"__@toStringTag@
|
|
538
|
+
"__@toStringTag@75984": {
|
|
539
539
|
"type": "string",
|
|
540
540
|
"const": "Uint8Array"
|
|
541
541
|
}
|
|
542
542
|
},
|
|
543
543
|
"required": [
|
|
544
544
|
"BYTES_PER_ELEMENT",
|
|
545
|
-
"__@toStringTag@
|
|
545
|
+
"__@toStringTag@75984",
|
|
546
546
|
"buffer",
|
|
547
547
|
"byteLength",
|
|
548
548
|
"byteOffset",
|
|
@@ -577,13 +577,13 @@
|
|
|
577
577
|
"byteLength": {
|
|
578
578
|
"type": "number"
|
|
579
579
|
},
|
|
580
|
-
"__@toStringTag@
|
|
580
|
+
"__@toStringTag@75984": {
|
|
581
581
|
"type": "string"
|
|
582
582
|
}
|
|
583
583
|
},
|
|
584
584
|
"additionalProperties": false,
|
|
585
585
|
"required": [
|
|
586
|
-
"__@toStringTag@
|
|
586
|
+
"__@toStringTag@75984",
|
|
587
587
|
"byteLength"
|
|
588
588
|
]
|
|
589
589
|
},
|
|
@@ -593,18 +593,18 @@
|
|
|
593
593
|
"byteLength": {
|
|
594
594
|
"type": "number"
|
|
595
595
|
},
|
|
596
|
-
"__@species@
|
|
596
|
+
"__@species@76085": {
|
|
597
597
|
"$ref": "#/definitions/SharedArrayBuffer"
|
|
598
598
|
},
|
|
599
|
-
"__@toStringTag@
|
|
599
|
+
"__@toStringTag@75984": {
|
|
600
600
|
"type": "string",
|
|
601
601
|
"const": "SharedArrayBuffer"
|
|
602
602
|
}
|
|
603
603
|
},
|
|
604
604
|
"additionalProperties": false,
|
|
605
605
|
"required": [
|
|
606
|
-
"__@species@
|
|
607
|
-
"__@toStringTag@
|
|
606
|
+
"__@species@76085",
|
|
607
|
+
"__@toStringTag@75984",
|
|
608
608
|
"byteLength"
|
|
609
609
|
]
|
|
610
610
|
},
|