@crawlee/core 4.0.0-beta.122 → 4.0.0-beta.124
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/autoscaling/concurrency_system.d.ts +2 -2
- package/autoscaling/index.d.ts +1 -1
- package/autoscaling/index.js +1 -1
- package/autoscaling/load_signal.d.ts +7 -6
- package/autoscaling/load_signal.js +2 -1
- package/autoscaling/snapshotter.d.ts +6 -6
- package/autoscaling/snapshotter.js +9 -9
- package/autoscaling/{client_load_signal.d.ts → storage_backend_load_signal.d.ts} +13 -12
- package/autoscaling/{client_load_signal.js → storage_backend_load_signal.js} +11 -11
- package/autoscaling/system_status.d.ts +8 -8
- package/autoscaling/system_status.js +2 -2
- package/crawlers/crawler_commons.d.ts +8 -54
- package/enqueue_links/enqueue_links.d.ts +33 -61
- package/enqueue_links/enqueue_links.js +35 -157
- package/enqueue_links/shared.d.ts +11 -4
- package/enqueue_links/shared.js +16 -1
- package/events/event_manager.js +2 -1
- package/package.json +6 -6
- package/request.d.ts +2 -2
- package/router.d.ts +5 -5
- package/storages/throttling_request_manager.d.ts +72 -49
- package/storages/throttling_request_manager.js +321 -130
|
@@ -53,8 +53,8 @@ export interface ConcurrencySystemOptions {
|
|
|
53
53
|
autoscaleIntervalSecs?: number;
|
|
54
54
|
/**
|
|
55
55
|
* The signals that tell the system whether the machine is overloaded: per-resource tuning for the built-in four
|
|
56
|
-
* (memory, event loop, CPU,
|
|
57
|
-
* your own. See {@link LoadSignalsOptions}.
|
|
56
|
+
* (memory, event loop, CPU, storage backend) plus any {@link LoadSignalsOptions.custom|`custom`}
|
|
57
|
+
* implementations of your own. See {@link LoadSignalsOptions}.
|
|
58
58
|
*/
|
|
59
59
|
loadSignals?: LoadSignalsOptions;
|
|
60
60
|
/**
|
package/autoscaling/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './autoscaled_pool.js';
|
|
2
2
|
export * from './concurrency_system.js';
|
|
3
|
-
export * from './client_load_signal.js';
|
|
4
3
|
export * from './cpu_load_signal.js';
|
|
5
4
|
export * from './event_loop_load_signal.js';
|
|
6
5
|
export * from './load_signal.js';
|
|
7
6
|
export * from './memory_load_signal.js';
|
|
8
7
|
export * from './snapshotter.js';
|
|
8
|
+
export * from './storage_backend_load_signal.js';
|
|
9
9
|
export * from './system_status.js';
|
package/autoscaling/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './autoscaled_pool.js';
|
|
2
2
|
export * from './concurrency_system.js';
|
|
3
|
-
export * from './client_load_signal.js';
|
|
4
3
|
export * from './cpu_load_signal.js';
|
|
5
4
|
export * from './event_loop_load_signal.js';
|
|
6
5
|
export * from './load_signal.js';
|
|
7
6
|
export * from './memory_load_signal.js';
|
|
8
7
|
export * from './snapshotter.js';
|
|
8
|
+
export * from './storage_backend_load_signal.js';
|
|
9
9
|
export * from './system_status.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LoadSignalInfo } from './system_status.js';
|
|
2
2
|
/**
|
|
3
3
|
* A snapshot of a resource's overload state at a point in time.
|
|
4
4
|
*/
|
|
@@ -22,7 +22,7 @@ export interface LoadSignalStartContext {
|
|
|
22
22
|
* A signal that reports whether a particular resource is overloaded. The {@link ConcurrencySystem} aggregates
|
|
23
23
|
* several of them — if any one reports overload, the system is overloaded.
|
|
24
24
|
*
|
|
25
|
-
* The built-in signals cover memory, CPU, event loop and storage
|
|
25
|
+
* The built-in signals cover memory, CPU, event loop and storage backend rate limits. Implement this interface to add
|
|
26
26
|
* your own (navigation timeouts, proxy health, …) and pass them via
|
|
27
27
|
* {@link LoadSignalsOptions.custom|`loadSignals.custom`}; {@link SnapshotStore} does the time-windowed
|
|
28
28
|
* bookkeeping if you want it. Each built-in is also a public class, so one can be *wrapped* rather than reimplemented
|
|
@@ -32,8 +32,8 @@ export interface LoadSignal {
|
|
|
32
32
|
/**
|
|
33
33
|
* This signal's key in the reported {@link SystemInfo}, also used in logging — so it must be unique among the
|
|
34
34
|
* signals of one {@link ConcurrencySystem}, which throws on a duplicate. The four built-in names (`memInfo`,
|
|
35
|
-
* `eventLoopInfo`, `cpuInfo`, `
|
|
36
|
-
* `loadSignalInfo` bag; taking one over means switching that built-in off.
|
|
35
|
+
* `eventLoopInfo`, `cpuInfo`, `storageBackendInfo`) land in the correspondingly named `SystemInfo` fields rather
|
|
36
|
+
* than the `loadSignalInfo` bag; taking one over means switching that built-in off.
|
|
37
37
|
*/
|
|
38
38
|
readonly name: string;
|
|
39
39
|
/**
|
|
@@ -79,7 +79,8 @@ export declare class SnapshotStore<T extends LoadSnapshot = LoadSnapshot> {
|
|
|
79
79
|
getSample(sampleDurationMillis?: number): T[];
|
|
80
80
|
/**
|
|
81
81
|
* Direct, unwindowed access to the underlying array — used by signals whose handler needs the previous snapshot
|
|
82
|
-
* to compute a delta (e.g. the event loop and
|
|
82
|
+
* to compute a delta (e.g. the event loop and storage backend signals read the last entry to measure change since
|
|
83
|
+
* it).
|
|
83
84
|
*/
|
|
84
85
|
getAll(): T[];
|
|
85
86
|
/**
|
|
@@ -96,4 +97,4 @@ export declare class SnapshotStore<T extends LoadSnapshot = LoadSnapshot> {
|
|
|
96
97
|
* evaluation logic used by `SystemStatus` for all signal types.
|
|
97
98
|
* @internal
|
|
98
99
|
*/
|
|
99
|
-
export declare function evaluateLoadSignalSample(sample: LoadSnapshot[], overloadedRatio: number):
|
|
100
|
+
export declare function evaluateLoadSignalSample(sample: LoadSnapshot[], overloadedRatio: number): LoadSignalInfo;
|
|
@@ -57,7 +57,8 @@ export class SnapshotStore {
|
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Direct, unwindowed access to the underlying array — used by signals whose handler needs the previous snapshot
|
|
60
|
-
* to compute a delta (e.g. the event loop and
|
|
60
|
+
* to compute a delta (e.g. the event loop and storage backend signals read the last entry to measure change since
|
|
61
|
+
* it).
|
|
61
62
|
*/
|
|
62
63
|
getAll() {
|
|
63
64
|
return this.#snapshots;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ClientLoadSignalOptions } from './client_load_signal.js';
|
|
2
1
|
import type { CpuLoadSignalOptions } from './cpu_load_signal.js';
|
|
3
2
|
import type { EventLoopLoadSignalOptions } from './event_loop_load_signal.js';
|
|
4
3
|
import type { LoadSignal, LoadSignalStartContext } from './load_signal.js';
|
|
5
4
|
import type { MemoryLoadSignalOptions } from './memory_load_signal.js';
|
|
5
|
+
import type { StorageBackendLoadSignalOptions } from './storage_backend_load_signal.js';
|
|
6
6
|
/**
|
|
7
7
|
* The load signals a {@link ConcurrencySystem} watches to decide whether the machine is overloaded.
|
|
8
8
|
*
|
|
@@ -31,11 +31,11 @@ export interface LoadSignalsOptions {
|
|
|
31
31
|
*/
|
|
32
32
|
cpu?: CpuLoadSignalOptions | false;
|
|
33
33
|
/**
|
|
34
|
-
* Tuning for the built-in {@link
|
|
35
|
-
* `false` to switch it off — worth doing when the storage backend reports no rate-limit statistics, since the
|
|
34
|
+
* Tuning for the built-in {@link StorageBackendLoadSignal} (snapshot interval + error limit + overload ratio),
|
|
35
|
+
* or `false` to switch it off — worth doing when the storage backend reports no rate-limit statistics, since the
|
|
36
36
|
* signal otherwise polls it every second to no purpose.
|
|
37
37
|
*/
|
|
38
|
-
|
|
38
|
+
storageBackend?: StorageBackendLoadSignalOptions | false;
|
|
39
39
|
/**
|
|
40
40
|
* Additional {@link LoadSignal} implementations — e.g. navigation timeouts or proxy health — evaluated
|
|
41
41
|
* alongside the built-in four. If any signal reports overload, the system counts as overloaded. Their lifecycle
|
|
@@ -53,8 +53,8 @@ export interface LoadSignalsOptions {
|
|
|
53
53
|
export type SnapshotterOptions = Omit<LoadSignalsOptions, 'custom'>;
|
|
54
54
|
/**
|
|
55
55
|
* Owns the four built-in {@link LoadSignal} instances — {@link MemoryLoadSignal},
|
|
56
|
-
* {@link EventLoopLoadSignal}, {@link CpuLoadSignal} and {@link
|
|
57
|
-
* that were not switched off and driving their shared lifecycle.
|
|
56
|
+
* {@link EventLoopLoadSignal}, {@link CpuLoadSignal} and {@link StorageBackendLoadSignal} — constructing
|
|
57
|
+
* the ones that were not switched off and driving their shared lifecycle.
|
|
58
58
|
*
|
|
59
59
|
* Configured indirectly through {@link ConcurrencySystemOptions.loadSignals|`loadSignals`}, whose per-signal bags
|
|
60
60
|
* are simply forwarded to the corresponding constructor.
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { ClientLoadSignal } from './client_load_signal.js';
|
|
2
1
|
import { CpuLoadSignal } from './cpu_load_signal.js';
|
|
3
2
|
import { EventLoopLoadSignal } from './event_loop_load_signal.js';
|
|
4
3
|
import { MemoryLoadSignal } from './memory_load_signal.js';
|
|
4
|
+
import { StorageBackendLoadSignal } from './storage_backend_load_signal.js';
|
|
5
5
|
/**
|
|
6
6
|
* Owns the four built-in {@link LoadSignal} instances — {@link MemoryLoadSignal},
|
|
7
|
-
* {@link EventLoopLoadSignal}, {@link CpuLoadSignal} and {@link
|
|
8
|
-
* that were not switched off and driving their shared lifecycle.
|
|
7
|
+
* {@link EventLoopLoadSignal}, {@link CpuLoadSignal} and {@link StorageBackendLoadSignal} — constructing
|
|
8
|
+
* the ones that were not switched off and driving their shared lifecycle.
|
|
9
9
|
*
|
|
10
10
|
* Configured indirectly through {@link ConcurrencySystemOptions.loadSignals|`loadSignals`}, whose per-signal bags
|
|
11
11
|
* are simply forwarded to the corresponding constructor.
|
|
12
12
|
* @internal
|
|
13
13
|
*/
|
|
14
14
|
export class Snapshotter {
|
|
15
|
-
// Absent when switched off through the corresponding option (e.g. `
|
|
15
|
+
// Absent when switched off through the corresponding option (e.g. `storageBackend: false`).
|
|
16
16
|
#memorySignal;
|
|
17
17
|
#eventLoopSignal;
|
|
18
18
|
#cpuSignal;
|
|
19
|
-
#
|
|
19
|
+
#storageBackendSignal;
|
|
20
20
|
/**
|
|
21
21
|
* Returns the enabled built-in signals, so `SystemStatus` can iterate them alongside any custom `LoadSignal`
|
|
22
22
|
* instances. Signals switched off through the options are simply absent — the system status reports them as
|
|
@@ -27,7 +27,7 @@ export class Snapshotter {
|
|
|
27
27
|
this.#memorySignal,
|
|
28
28
|
this.#eventLoopSignal,
|
|
29
29
|
this.#cpuSignal,
|
|
30
|
-
this.#
|
|
30
|
+
this.#storageBackendSignal,
|
|
31
31
|
];
|
|
32
32
|
return builtin.filter((signal) => signal !== undefined);
|
|
33
33
|
}
|
|
@@ -35,7 +35,7 @@ export class Snapshotter {
|
|
|
35
35
|
* @param [options] All `Snapshotter` configuration options.
|
|
36
36
|
*/
|
|
37
37
|
constructor(options = {}) {
|
|
38
|
-
const { memory = {}, eventLoop = {}, cpu = {},
|
|
38
|
+
const { memory = {}, eventLoop = {}, cpu = {}, storageBackend = {} } = options;
|
|
39
39
|
// Each signal resolves its own ambient dependencies when started, and is told the window it will be sampled
|
|
40
40
|
// over then too - so there is nothing to thread in here beyond the caller's tuning.
|
|
41
41
|
if (memory !== false)
|
|
@@ -44,8 +44,8 @@ export class Snapshotter {
|
|
|
44
44
|
this.#eventLoopSignal = new EventLoopLoadSignal(eventLoop);
|
|
45
45
|
if (cpu !== false)
|
|
46
46
|
this.#cpuSignal = new CpuLoadSignal(cpu);
|
|
47
|
-
if (
|
|
48
|
-
this.#
|
|
47
|
+
if (storageBackend !== false)
|
|
48
|
+
this.#storageBackendSignal = new StorageBackendLoadSignal(storageBackend);
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* Starts capturing snapshots at configured intervals. The `context` carries the sample window the signals will
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import type { LoadSignal, LoadSignalStartContext, LoadSnapshot } from './load_signal.js';
|
|
2
2
|
/**
|
|
3
|
-
* A snapshot produced by the built-in
|
|
3
|
+
* A snapshot produced by the built-in storage backend (rate-limit) signal.
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
6
|
-
export interface
|
|
6
|
+
export interface StorageBackendSnapshot extends LoadSnapshot {
|
|
7
7
|
rateLimitErrorCount: number;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* Tuning for the built-in **
|
|
11
|
-
*
|
|
10
|
+
* Tuning for the built-in **storage backend** (rate-limit) load signal, as accepted both by
|
|
11
|
+
* {@link StorageBackendLoadSignal} and by the
|
|
12
|
+
* {@link LoadSignalsOptions.storageBackend|`storageBackend`} shorthand on {@link LoadSignalsOptions}.
|
|
12
13
|
*/
|
|
13
|
-
export interface
|
|
14
|
+
export interface StorageBackendLoadSignalOptions {
|
|
14
15
|
/**
|
|
15
|
-
* Defines the interval of checking the current state of the
|
|
16
|
+
* Defines the interval of checking the current state of the storage backend, in seconds.
|
|
16
17
|
* @default 1
|
|
17
18
|
*/
|
|
18
19
|
snapshotIntervalSecs?: number;
|
|
@@ -22,7 +23,7 @@ export interface ClientLoadSignalOptions {
|
|
|
22
23
|
*/
|
|
23
24
|
maxErrors?: number;
|
|
24
25
|
/**
|
|
25
|
-
* Maximum ratio of overloaded snapshots in a sample before the
|
|
26
|
+
* Maximum ratio of overloaded snapshots in a sample before the storage backend counts as overloaded.
|
|
26
27
|
* @default 0.3
|
|
27
28
|
*/
|
|
28
29
|
overloadedRatio?: number;
|
|
@@ -33,16 +34,16 @@ export interface ClientLoadSignalOptions {
|
|
|
33
34
|
*
|
|
34
35
|
* Built by default; construct one yourself only to wrap or adapt it — see {@link LoadSignal}.
|
|
35
36
|
*
|
|
36
|
-
* Switch it off entirely ({@link LoadSignalsOptions.
|
|
37
|
-
* rate-limit statistics, since it otherwise polls it every second to no purpose.
|
|
37
|
+
* Switch it off entirely ({@link LoadSignalsOptions.storageBackend|`storageBackend: false`}) if the storage backend
|
|
38
|
+
* reports no rate-limit statistics, since it otherwise polls it every second to no purpose.
|
|
38
39
|
*
|
|
39
40
|
* @category Scaling
|
|
40
41
|
*/
|
|
41
|
-
export declare class
|
|
42
|
+
export declare class StorageBackendLoadSignal implements LoadSignal {
|
|
42
43
|
#private;
|
|
43
|
-
readonly name = "
|
|
44
|
+
readonly name = "storageBackendInfo";
|
|
44
45
|
readonly overloadedRatio: number;
|
|
45
|
-
constructor(options?:
|
|
46
|
+
constructor(options?: StorageBackendLoadSignalOptions);
|
|
46
47
|
start(context: LoadSignalStartContext): Promise<void>;
|
|
47
48
|
stop(): Promise<void>;
|
|
48
49
|
getSample(sampleDurationMillis?: number): LoadSnapshot[];
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { betterClearInterval, betterSetInterval } from '@apify/utilities';
|
|
2
2
|
import { serviceLocator } from '../service_locator.js';
|
|
3
3
|
import { SnapshotStore } from './load_signal.js';
|
|
4
|
-
const
|
|
4
|
+
const RATE_LIMIT_ERROR_RETRY_COUNT = 2;
|
|
5
5
|
/**
|
|
6
6
|
* Periodically checks the storage backend for rate-limit errors (HTTP 429) and reports overload when the error delta
|
|
7
7
|
* exceeds a threshold.
|
|
8
8
|
*
|
|
9
9
|
* Built by default; construct one yourself only to wrap or adapt it — see {@link LoadSignal}.
|
|
10
10
|
*
|
|
11
|
-
* Switch it off entirely ({@link LoadSignalsOptions.
|
|
12
|
-
* rate-limit statistics, since it otherwise polls it every second to no purpose.
|
|
11
|
+
* Switch it off entirely ({@link LoadSignalsOptions.storageBackend|`storageBackend: false`}) if the storage backend
|
|
12
|
+
* reports no rate-limit statistics, since it otherwise polls it every second to no purpose.
|
|
13
13
|
*
|
|
14
14
|
* @category Scaling
|
|
15
15
|
*/
|
|
16
|
-
export class
|
|
17
|
-
name = '
|
|
16
|
+
export class StorageBackendLoadSignal {
|
|
17
|
+
name = 'storageBackendInfo';
|
|
18
18
|
overloadedRatio;
|
|
19
19
|
#store = new SnapshotStore();
|
|
20
20
|
#intervalMillis;
|
|
21
21
|
#maxErrors;
|
|
22
22
|
#interval;
|
|
23
|
-
#
|
|
23
|
+
#storageBackend;
|
|
24
24
|
constructor(options = {}) {
|
|
25
25
|
this.overloadedRatio = options.overloadedRatio ?? 0.3;
|
|
26
26
|
this.#intervalMillis = (options.snapshotIntervalSecs ?? 1) * 1000;
|
|
@@ -30,18 +30,18 @@ export class ClientLoadSignal {
|
|
|
30
30
|
async start(context) {
|
|
31
31
|
this.#store.useSampleWindow(context.maxSampleWindowMillis);
|
|
32
32
|
// A new session starts from a clean slate, or its first measurement diffs the error count against the previous
|
|
33
|
-
// session's — possibly against a different backend, since
|
|
33
|
+
// session's — possibly against a different backend, since it is resolved afresh just below.
|
|
34
34
|
this.#store.clear();
|
|
35
35
|
// Resolved here rather than in the constructor, where asking for the backend would instantiate a default one
|
|
36
36
|
// as a side effect - long before the crawler that owns the run has had a chance to register its own.
|
|
37
|
-
this.#
|
|
37
|
+
this.#storageBackend = serviceLocator.getStorageBackend();
|
|
38
38
|
this.#interval = betterSetInterval(this.handle, this.#intervalMillis);
|
|
39
39
|
}
|
|
40
40
|
async stop() {
|
|
41
41
|
if (this.#interval)
|
|
42
42
|
betterClearInterval(this.#interval);
|
|
43
43
|
this.#interval = undefined;
|
|
44
|
-
this.#
|
|
44
|
+
this.#storageBackend = undefined;
|
|
45
45
|
}
|
|
46
46
|
getSample(sampleDurationMillis) {
|
|
47
47
|
return this.#store.getSample(sampleDurationMillis);
|
|
@@ -53,8 +53,8 @@ export class ClientLoadSignal {
|
|
|
53
53
|
*/
|
|
54
54
|
handle(intervalCallback) {
|
|
55
55
|
const now = new Date();
|
|
56
|
-
const allErrorCounts = this.#
|
|
57
|
-
const currentErrCount = allErrorCounts[
|
|
56
|
+
const allErrorCounts = this.#storageBackend?.stats?.rateLimitErrors ?? [];
|
|
57
|
+
const currentErrCount = allErrorCounts[RATE_LIMIT_ERROR_RETRY_COUNT] || 0;
|
|
58
58
|
const snapshot = {
|
|
59
59
|
createdAt: now,
|
|
60
60
|
isOverloaded: false,
|
|
@@ -6,10 +6,10 @@ import type { Snapshotter } from './snapshotter.js';
|
|
|
6
6
|
export interface SystemInfo {
|
|
7
7
|
/** If false, system is being overloaded. */
|
|
8
8
|
isSystemIdle: boolean;
|
|
9
|
-
memInfo:
|
|
10
|
-
eventLoopInfo:
|
|
11
|
-
cpuInfo:
|
|
12
|
-
|
|
9
|
+
memInfo: LoadSignalInfo;
|
|
10
|
+
eventLoopInfo: LoadSignalInfo;
|
|
11
|
+
cpuInfo: LoadSignalInfo;
|
|
12
|
+
storageBackendInfo: LoadSignalInfo;
|
|
13
13
|
memTotalBytes?: number;
|
|
14
14
|
memCurrentBytes?: number;
|
|
15
15
|
/**
|
|
@@ -31,7 +31,7 @@ export interface SystemInfo {
|
|
|
31
31
|
* Status of additional load signals beyond the built-in four.
|
|
32
32
|
* Keys are `LoadSignal.name` values, values are overload info.
|
|
33
33
|
*/
|
|
34
|
-
loadSignalInfo?: Record<string,
|
|
34
|
+
loadSignalInfo?: Record<string, LoadSignalInfo>;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* How far back the *current* system status looks by default — the window that gates task dispatch.
|
|
@@ -69,12 +69,12 @@ export interface SystemStatusOptions {
|
|
|
69
69
|
/**
|
|
70
70
|
* Additional load signals to include in the system status evaluation.
|
|
71
71
|
* These are evaluated alongside the built-in memory, CPU, event loop,
|
|
72
|
-
* and
|
|
73
|
-
* considered overloaded. Each signal carries its own overload ratio.
|
|
72
|
+
* and storage backend signals. If any signal reports overload, the system
|
|
73
|
+
* is considered overloaded. Each signal carries its own overload ratio.
|
|
74
74
|
*/
|
|
75
75
|
loadSignals?: LoadSignal[];
|
|
76
76
|
}
|
|
77
|
-
export interface
|
|
77
|
+
export interface LoadSignalInfo {
|
|
78
78
|
isOverloaded: boolean;
|
|
79
79
|
limitRatio: number;
|
|
80
80
|
actualRatio: number;
|
|
@@ -15,7 +15,7 @@ const BUILTIN_SIGNAL_OPTION_KEYS = {
|
|
|
15
15
|
memInfo: 'memory',
|
|
16
16
|
eventLoopInfo: 'eventLoop',
|
|
17
17
|
cpuInfo: 'cpu',
|
|
18
|
-
|
|
18
|
+
storageBackendInfo: 'storageBackend',
|
|
19
19
|
};
|
|
20
20
|
const BUILTIN_SIGNAL_NAMES = new Set(Object.keys(BUILTIN_SIGNAL_OPTION_KEYS));
|
|
21
21
|
/**
|
|
@@ -114,7 +114,7 @@ export class SystemStatus {
|
|
|
114
114
|
memInfo: { isOverloaded: false, limitRatio: 0, actualRatio: 0 },
|
|
115
115
|
eventLoopInfo: { isOverloaded: false, limitRatio: 0, actualRatio: 0 },
|
|
116
116
|
cpuInfo: { isOverloaded: false, limitRatio: 0, actualRatio: 0 },
|
|
117
|
-
|
|
117
|
+
storageBackendInfo: { isOverloaded: false, limitRatio: 0, actualRatio: 0 },
|
|
118
118
|
};
|
|
119
119
|
let loadSignalInfo;
|
|
120
120
|
for (const signal of this.#signals) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Dictionary, HttpRequestOptions, ISession, ProxyInfo, SendRequestOptions } from '@crawlee/types';
|
|
2
|
-
import type { ReadonlyDeep
|
|
3
|
-
import type {
|
|
2
|
+
import type { ReadonlyDeep } from 'type-fest';
|
|
3
|
+
import type { EnqueueUrlsOptions } from '../enqueue_links/enqueue_links.js';
|
|
4
4
|
import type { CrawleeLogger } from '../log.js';
|
|
5
5
|
import type { Request, RequestOptions, Source } from '../request.js';
|
|
6
6
|
import type { StorageIdentifier } from '../storages/storage_instance_manager.js';
|
|
7
7
|
import type { Dataset } from '../storages/dataset.js';
|
|
8
8
|
import type { KeyValueStore } from '../storages/key_value_store.js';
|
|
9
|
-
import type {
|
|
9
|
+
import type { AddRequestsBatchedResult } from '../storages/request_queue.js';
|
|
10
10
|
/** @internal */
|
|
11
11
|
export type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
12
12
|
/**
|
|
@@ -37,7 +37,7 @@ export type TypedRequestsLike<Routes extends Record<keyof Routes, Dictionary>> =
|
|
|
37
37
|
* The label-aware `addRequests` method signature exposed on a request handler's context when the crawler is
|
|
38
38
|
* bound to a typed router. Mirrors {@link RestrictedCrawlingContext.addRequests} with typed sources.
|
|
39
39
|
*/
|
|
40
|
-
export type TypedContextAddRequests<Routes extends Record<keyof Routes, Dictionary>> = (requestsLike: ReadonlyDeep<LabeledSource<Routes>[]>, options?: ReadonlyDeep<
|
|
40
|
+
export type TypedContextAddRequests<Routes extends Record<keyof Routes, Dictionary>> = (requestsLike: ReadonlyDeep<LabeledSource<Routes>[]>, options?: ReadonlyDeep<EnqueueUrlsOptions>) => Promise<AddRequestsBatchedResult>;
|
|
41
41
|
/**
|
|
42
42
|
* An `enqueueLinks`-options object with its `label`/`userData` retyped according to a router's route map: a
|
|
43
43
|
* declared `label` requires the matching `userData` shape (unknown labels are rejected), while unlabeled
|
|
@@ -87,36 +87,15 @@ export interface RestrictedCrawlingContext<UserData extends Dictionary = Diction
|
|
|
87
87
|
*/
|
|
88
88
|
pushData(data: ReadonlyDeep<Parameters<Dataset['pushData']>[0]>, datasetIdentifier?: string | StorageIdentifier): Promise<void>;
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
91
|
-
* currently used by the crawler.
|
|
90
|
+
* Add requests directly to the request queue currently used by the crawler.
|
|
92
91
|
*
|
|
93
|
-
* Optionally, the function allows you to filter the target
|
|
94
|
-
*
|
|
95
|
-
* Check out the [Crawl a website with relative links](https://crawlee.dev/js/docs/examples/crawl-relative-links) example
|
|
96
|
-
* for more details regarding its usage.
|
|
97
|
-
*
|
|
98
|
-
* **Example usage**
|
|
99
|
-
*
|
|
100
|
-
* ```ts
|
|
101
|
-
* async requestHandler({ enqueueLinks }) {
|
|
102
|
-
* await enqueueLinks({
|
|
103
|
-
* include: [
|
|
104
|
-
* 'https://www.example.com/handbags/*',
|
|
105
|
-
* ],
|
|
106
|
-
* });
|
|
107
|
-
* },
|
|
108
|
-
* ```
|
|
109
|
-
*
|
|
110
|
-
* @param [options] All `enqueueLinks()` parameters are passed via an options object.
|
|
111
|
-
*/
|
|
112
|
-
enqueueLinks: (options: ReadonlyDeep<Omit<SetRequired<EnqueueLinksOptions, 'urls'>, 'requestManager' | 'robotsTxtFile'>>) => Promise<unknown>;
|
|
113
|
-
/**
|
|
114
|
-
* Add requests directly to the request queue.
|
|
92
|
+
* Optionally, the function allows you to filter the target URLs using an array of glob or regexp patterns,
|
|
93
|
+
* the same way {@link CrawlingContext.enqueueLinks|`enqueueLinks`} does for extracted links.
|
|
115
94
|
*
|
|
116
95
|
* @param requests The requests to add
|
|
117
96
|
* @param options Options for the request queue
|
|
118
97
|
*/
|
|
119
|
-
addRequests: (requestsLike: ReadonlyDeep<(string | Source)[]>, options?: ReadonlyDeep<
|
|
98
|
+
addRequests: (requestsLike: ReadonlyDeep<(string | Source)[]>, options?: ReadonlyDeep<EnqueueUrlsOptions>) => Promise<AddRequestsBatchedResult>;
|
|
120
99
|
/**
|
|
121
100
|
* Returns the state - a piece of mutable persistent data shared across all the request handler runs.
|
|
122
101
|
*/
|
|
@@ -131,31 +110,6 @@ export interface RestrictedCrawlingContext<UserData extends Dictionary = Diction
|
|
|
131
110
|
log: CrawleeLogger;
|
|
132
111
|
}
|
|
133
112
|
export interface CrawlingContext<UserData extends Dictionary = Dictionary> extends RestrictedCrawlingContext<UserData> {
|
|
134
|
-
/**
|
|
135
|
-
* This function automatically finds and enqueues links from the current page, adding them to the {@link RequestQueue}
|
|
136
|
-
* currently used by the crawler.
|
|
137
|
-
*
|
|
138
|
-
* Optionally, the function allows you to filter the target links' URLs using an array of glob or regexp patterns.
|
|
139
|
-
*
|
|
140
|
-
* Check out the [Crawl a website with relative links](https://crawlee.dev/js/docs/examples/crawl-relative-links) example
|
|
141
|
-
* for more details regarding its usage.
|
|
142
|
-
*
|
|
143
|
-
* **Example usage**
|
|
144
|
-
*
|
|
145
|
-
* ```ts
|
|
146
|
-
* async requestHandler({ enqueueLinks }) {
|
|
147
|
-
* await enqueueLinks({
|
|
148
|
-
* include: [
|
|
149
|
-
* 'https://www.example.com/handbags/*',
|
|
150
|
-
* ],
|
|
151
|
-
* });
|
|
152
|
-
* },
|
|
153
|
-
* ```
|
|
154
|
-
*
|
|
155
|
-
* @param [options] All `enqueueLinks()` parameters are passed via an options object.
|
|
156
|
-
* @returns Promise that resolves to {@link BatchAddRequestsResult} object.
|
|
157
|
-
*/
|
|
158
|
-
enqueueLinks(options: ReadonlyDeep<Omit<SetRequired<EnqueueLinksOptions, 'urls'>, 'requestManager' | 'robotsTxtFile'>> & Pick<EnqueueLinksOptions, 'requestManager' | 'robotsTxtFile'>): Promise<unknown>;
|
|
159
113
|
/**
|
|
160
114
|
* Fires HTTP request via the internal HTTP client, allowing to override the request options on the fly.
|
|
161
115
|
*
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import type { Dictionary } from '@crawlee/types';
|
|
2
|
+
import type { RequestQueueOperationOptions } from '../storages/request_queue.js';
|
|
3
|
+
import type { RequestTransform, SkippedRequestCallback, UrlPatternInput, UrlPatternObject } from './shared.js';
|
|
4
|
+
/**
|
|
5
|
+
* Options shared by the `extractLinks()` context helper across crawler types.
|
|
6
|
+
*/
|
|
7
|
+
export interface ExtractLinksOptions {
|
|
8
|
+
/** A CSS selector matching links to be extracted. */
|
|
9
|
+
selector?: string;
|
|
10
|
+
/**
|
|
11
|
+
* A base URL that will be used to resolve relative URLs when using Cheerio. Ignored when using Puppeteer,
|
|
12
|
+
* since the relative URL resolution is done inside the browser automatically.
|
|
13
|
+
*/
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Options accepted by the `enqueueUrls()` context helper exposed by `BasicCrawler`.
|
|
18
|
+
*/
|
|
19
|
+
export interface EnqueueUrlsOptions extends RequestQueueOperationOptions {
|
|
9
20
|
/** Limit the amount of actually enqueued URLs to this number. Useful for testing across the entire crawling scope. */
|
|
10
21
|
limit?: number;
|
|
11
|
-
/** An array of URLs to enqueue. */
|
|
12
|
-
urls?: readonly string[];
|
|
13
|
-
/** A request manager to which the URLs will be enqueued. */
|
|
14
|
-
requestManager?: IRequestManager;
|
|
15
|
-
/** A CSS selector matching links to be enqueued. */
|
|
16
|
-
selector?: string;
|
|
17
22
|
/** Sets {@link Request.userData} for newly enqueued requests. */
|
|
18
23
|
userData?: Dictionary;
|
|
19
24
|
/**
|
|
@@ -30,8 +35,7 @@ export interface EnqueueLinksOptions extends RequestQueueOperationOptions {
|
|
|
30
35
|
*/
|
|
31
36
|
skipNavigation?: boolean;
|
|
32
37
|
/**
|
|
33
|
-
* A base URL that will be used to resolve relative URLs
|
|
34
|
-
* since the relative URL resolution is done inside the browser automatically.
|
|
38
|
+
* A base URL that will be used to resolve relative URLs.
|
|
35
39
|
*/
|
|
36
40
|
baseUrl?: string;
|
|
37
41
|
/**
|
|
@@ -42,11 +46,11 @@ export interface EnqueueLinksOptions extends RequestQueueOperationOptions {
|
|
|
42
46
|
* Glob matching is always case-insensitive.
|
|
43
47
|
* If you need case-sensitive matching, use a `RegExp`.
|
|
44
48
|
*
|
|
45
|
-
* The patterns are combined with the {@link
|
|
49
|
+
* The patterns are combined with the {@link EnqueueUrlsOptions.strategy|`strategy`} using AND logic - a URL
|
|
46
50
|
* must match at least one `include` pattern **and** satisfy the strategy to be enqueued. To match URLs across
|
|
47
51
|
* hostnames, pass an explicit {@link EnqueueStrategy.All} strategy.
|
|
48
52
|
*
|
|
49
|
-
* If `undefined`, the links are enqueued based on the {@link
|
|
53
|
+
* If `undefined`, the links are enqueued based on the {@link EnqueueUrlsOptions.strategy|`strategy`} alone.
|
|
50
54
|
* Passing an empty array is not allowed.
|
|
51
55
|
*/
|
|
52
56
|
include?: readonly UrlPatternInput[];
|
|
@@ -106,25 +110,12 @@ export interface EnqueueLinksOptions extends RequestQueueOperationOptions {
|
|
|
106
110
|
*
|
|
107
111
|
* @default EnqueueStrategy.SameHostname
|
|
108
112
|
*/
|
|
109
|
-
strategy?:
|
|
113
|
+
strategy?: EnqueueStrategyOption;
|
|
110
114
|
/**
|
|
111
115
|
* By default, only the first batch (1000) of found requests will be added to the queue before resolving the call.
|
|
112
116
|
* You can use this option to wait for adding all of them.
|
|
113
117
|
*/
|
|
114
118
|
waitForAllRequestsToBeAdded?: boolean;
|
|
115
|
-
/**
|
|
116
|
-
* RobotsTxtFile instance for the current request that triggered the `enqueueLinks`.
|
|
117
|
-
* If provided, disallowed URLs will be ignored.
|
|
118
|
-
*/
|
|
119
|
-
robotsTxtFile?: Pick<RobotsTxtFile, 'isAllowed'>;
|
|
120
|
-
/**
|
|
121
|
-
* Mirrors {@link BasicCrawlerOptions.respectRobotsTxtFile}: pass `false` to disable filtering or
|
|
122
|
-
* `{ userAgent }` to evaluate rules for a specific user-agent. Defaults to `*` when
|
|
123
|
-
* {@link EnqueueLinksOptions.robotsTxtFile|`robotsTxtFile`} is provided.
|
|
124
|
-
*/
|
|
125
|
-
respectRobotsTxtFile?: boolean | {
|
|
126
|
-
userAgent?: string;
|
|
127
|
-
};
|
|
128
119
|
/**
|
|
129
120
|
* When a request is skipped for some reason, you can use this callback to act on it.
|
|
130
121
|
* This is currently fired for requests skipped
|
|
@@ -134,6 +125,8 @@ export interface EnqueueLinksOptions extends RequestQueueOperationOptions {
|
|
|
134
125
|
*/
|
|
135
126
|
onSkippedRequest?: SkippedRequestCallback;
|
|
136
127
|
}
|
|
128
|
+
/** The combined options accepted by a crawler context's `enqueueLinks()` helper: `extractLinks()` + `enqueueUrls()`. */
|
|
129
|
+
export type EnqueueLinksOptions = ExtractLinksOptions & EnqueueUrlsOptions;
|
|
137
130
|
/**
|
|
138
131
|
* The different enqueueing strategies available.
|
|
139
132
|
*
|
|
@@ -185,34 +178,8 @@ export declare enum EnqueueStrategy {
|
|
|
185
178
|
*/
|
|
186
179
|
SameOrigin = "same-origin"
|
|
187
180
|
}
|
|
188
|
-
/**
|
|
189
|
-
|
|
190
|
-
* you should use the context-aware `enqueueLinks` function provided on the crawler contexts.
|
|
191
|
-
*
|
|
192
|
-
* Optionally, the function allows you to filter the target links' URLs using an array of glob or regexp patterns.
|
|
193
|
-
*
|
|
194
|
-
* **Example usage**
|
|
195
|
-
*
|
|
196
|
-
* ```javascript
|
|
197
|
-
* await enqueueLinks({
|
|
198
|
-
* urls: aListOfFoundUrls,
|
|
199
|
-
* requestManager,
|
|
200
|
-
* selector: 'a.product-detail',
|
|
201
|
-
* include: [
|
|
202
|
-
* 'https://www.example.com/handbags/*',
|
|
203
|
-
* 'https://www.example.com/purses/*'
|
|
204
|
-
* ],
|
|
205
|
-
* });
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @param options All `enqueueLinks()` parameters are passed via an options object.
|
|
209
|
-
* @returns Promise that resolves to {@link BatchAddRequestsResult} object.
|
|
210
|
-
*/
|
|
211
|
-
export declare function enqueueLinks(options: SetRequired<Omit<EnqueueLinksOptions, 'requestManager'>, 'urls'> & {
|
|
212
|
-
requestManager: {
|
|
213
|
-
addRequestsBatched: (requests: Request<Dictionary>[], options: AddRequestsBatchedOptions) => Promise<AddRequestsBatchedResult>;
|
|
214
|
-
};
|
|
215
|
-
}): Promise<BatchAddRequestsResult>;
|
|
181
|
+
/** The `strategy` option accepted by {@link ExtractLinksOptions} and {@link EnqueueUrlsOptions}. */
|
|
182
|
+
export type EnqueueStrategyOption = EnqueueStrategy | 'all' | 'same-domain' | 'same-hostname' | 'same-origin';
|
|
216
183
|
/**
|
|
217
184
|
* @internal
|
|
218
185
|
* This method helps resolve the baseUrl that will be used for filtering in {@link enqueueLinks}.
|
|
@@ -227,7 +194,12 @@ export declare function resolveBaseUrlForEnqueueLinksFiltering({ enqueueStrategy
|
|
|
227
194
|
*/
|
|
228
195
|
export interface ResolveBaseUrl {
|
|
229
196
|
userProvidedBaseUrl?: string;
|
|
230
|
-
enqueueStrategy?:
|
|
197
|
+
enqueueStrategy?: EnqueueStrategyOption;
|
|
231
198
|
originalRequestUrl: string;
|
|
232
199
|
finalRequestUrl?: string;
|
|
233
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* @internal
|
|
203
|
+
* Builds the glob patterns a URL must match to satisfy the given enqueue `strategy`, anchored at `baseUrl`.
|
|
204
|
+
*/
|
|
205
|
+
export declare function buildEnqueueStrategyPatterns(baseUrl: string, strategy: EnqueueStrategyOption): UrlPatternObject[];
|