@crawlee/core 4.0.0-beta.8 → 4.0.0-beta.81
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/README.md +17 -13
- package/autoscaling/autoscaled_pool.d.ts +14 -15
- package/autoscaling/autoscaled_pool.js +37 -36
- package/autoscaling/client_load_signal.d.ts +25 -0
- package/autoscaling/client_load_signal.js +36 -0
- package/autoscaling/cpu_load_signal.d.ts +28 -0
- package/autoscaling/cpu_load_signal.js +24 -0
- package/autoscaling/event_loop_load_signal.d.ts +23 -0
- package/autoscaling/event_loop_load_signal.js +35 -0
- package/autoscaling/index.d.ts +5 -1
- package/autoscaling/index.js +5 -1
- package/autoscaling/load_signal.d.ts +99 -0
- package/autoscaling/load_signal.js +135 -0
- package/autoscaling/memory_load_signal.d.ts +43 -0
- package/autoscaling/memory_load_signal.js +102 -0
- package/autoscaling/snapshotter.d.ts +29 -91
- package/autoscaling/snapshotter.js +65 -204
- package/autoscaling/system_status.d.ts +22 -37
- package/autoscaling/system_status.js +49 -87
- package/configuration.d.ts +88 -228
- package/configuration.js +162 -224
- package/cookie_utils.d.ts +4 -3
- package/cookie_utils.js +20 -13
- package/crawlers/context_pipeline.d.ts +70 -0
- package/crawlers/context_pipeline.js +122 -0
- package/crawlers/crawler_commons.d.ts +20 -30
- package/crawlers/crawler_commons.js +12 -21
- package/crawlers/crawler_utils.d.ts +2 -3
- package/crawlers/crawler_utils.js +1 -2
- package/crawlers/error_snapshotter.d.ts +3 -3
- package/crawlers/error_snapshotter.js +2 -3
- package/crawlers/error_tracker.d.ts +2 -2
- package/crawlers/error_tracker.js +0 -1
- package/crawlers/index.d.ts +1 -2
- package/crawlers/index.js +1 -2
- package/crawlers/internals/types.d.ts +7 -0
- package/crawlers/internals/types.js +1 -0
- package/crawlers/statistics.d.ts +28 -23
- package/crawlers/statistics.js +38 -34
- package/enqueue_links/enqueue_links.d.ts +44 -22
- package/enqueue_links/enqueue_links.js +51 -30
- package/enqueue_links/index.d.ts +0 -1
- package/enqueue_links/index.js +0 -1
- package/enqueue_links/shared.d.ts +25 -9
- package/enqueue_links/shared.js +69 -38
- package/errors.d.ts +53 -4
- package/errors.js +70 -5
- package/events/event_manager.d.ts +34 -8
- package/events/event_manager.js +8 -10
- package/events/index.d.ts +0 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -5
- package/events/local_event_manager.js +37 -40
- package/index.d.ts +4 -3
- package/index.js +3 -2
- package/log.d.ts +82 -3
- package/log.js +102 -1
- package/memory-storage/consts.d.ts +4 -0
- package/memory-storage/consts.js +4 -0
- package/memory-storage/index.d.ts +1 -0
- package/memory-storage/index.js +1 -0
- package/memory-storage/memory-storage.d.ts +46 -0
- package/memory-storage/memory-storage.js +136 -0
- package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
- package/memory-storage/resource-clients/common/base-client.js +6 -0
- package/memory-storage/resource-clients/dataset.d.ts +40 -0
- package/memory-storage/resource-clients/dataset.js +113 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
- package/memory-storage/resource-clients/key-value-store.js +203 -0
- package/memory-storage/resource-clients/request-queue.d.ts +96 -0
- package/memory-storage/resource-clients/request-queue.js +421 -0
- package/memory-storage/utils.d.ts +17 -0
- package/memory-storage/utils.js +42 -0
- package/package.json +12 -10
- package/proxy_configuration.d.ts +29 -152
- package/proxy_configuration.js +21 -173
- package/recoverable_state.d.ts +120 -0
- package/recoverable_state.js +141 -0
- package/request.d.ts +84 -13
- package/request.js +107 -28
- package/router.d.ts +118 -16
- package/router.js +124 -30
- package/serialization.d.ts +0 -1
- package/serialization.js +1 -2
- package/service_locator.d.ts +156 -0
- package/service_locator.js +238 -0
- package/session_pool/consts.d.ts +1 -2
- package/session_pool/consts.js +1 -2
- package/session_pool/errors.d.ts +0 -1
- package/session_pool/errors.js +0 -1
- package/session_pool/fingerprint.d.ts +9 -0
- package/session_pool/fingerprint.js +30 -0
- package/session_pool/index.d.ts +0 -2
- package/session_pool/index.js +0 -2
- package/session_pool/session.d.ts +37 -75
- package/session_pool/session.js +49 -102
- package/session_pool/session_pool.d.ts +85 -90
- package/session_pool/session_pool.js +131 -120
- package/storages/access_checking.d.ts +0 -1
- package/storages/access_checking.js +5 -2
- package/storages/dataset.d.ts +101 -51
- package/storages/dataset.js +168 -126
- package/storages/index.d.ts +8 -7
- package/storages/index.js +6 -7
- package/storages/key_value_store.d.ts +165 -36
- package/storages/key_value_store.js +269 -122
- package/storages/key_value_store_codec.d.ts +32 -0
- package/storages/key_value_store_codec.js +113 -0
- package/storages/request_dedup_cache.d.ts +23 -0
- package/storages/request_dedup_cache.js +48 -0
- package/storages/request_list.d.ts +53 -97
- package/storages/request_list.js +99 -75
- package/storages/request_loader.d.ts +96 -0
- package/storages/request_loader.js +1 -0
- package/storages/request_manager.d.ts +33 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +106 -0
- package/storages/request_manager_tandem.js +197 -0
- package/storages/request_queue.d.ts +290 -47
- package/storages/request_queue.js +628 -215
- package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +28 -24
- package/storages/{sitemap_request_list.js → sitemap_request_loader.js} +49 -46
- package/storages/storage_instance_manager.d.ts +91 -0
- package/storages/storage_instance_manager.js +258 -0
- package/storages/storage_stats.d.ts +48 -0
- package/storages/storage_stats.js +29 -0
- package/storages/utils.d.ts +51 -6
- package/storages/utils.js +60 -9
- package/system-info/cpu-info.d.ts +67 -0
- package/system-info/cpu-info.js +216 -0
- package/system-info/memory-info.d.ts +31 -0
- package/system-info/memory-info.js +115 -0
- package/system-info/ps-tree.d.ts +17 -0
- package/system-info/ps-tree.js +144 -0
- package/system-info/runtime.d.ts +14 -0
- package/system-info/runtime.js +80 -0
- package/typedefs.d.ts +1 -2
- package/typedefs.js +0 -1
- package/validators.d.ts +8 -1
- package/validators.js +10 -3
- package/autoscaling/autoscaled_pool.d.ts.map +0 -1
- package/autoscaling/autoscaled_pool.js.map +0 -1
- package/autoscaling/index.d.ts.map +0 -1
- package/autoscaling/index.js.map +0 -1
- package/autoscaling/snapshotter.d.ts.map +0 -1
- package/autoscaling/snapshotter.js.map +0 -1
- package/autoscaling/system_status.d.ts.map +0 -1
- package/autoscaling/system_status.js.map +0 -1
- package/configuration.d.ts.map +0 -1
- package/configuration.js.map +0 -1
- package/cookie_utils.d.ts.map +0 -1
- package/cookie_utils.js.map +0 -1
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.js.map +0 -1
- package/crawlers/crawler_extension.d.ts +0 -12
- package/crawlers/crawler_extension.d.ts.map +0 -1
- package/crawlers/crawler_extension.js +0 -14
- package/crawlers/crawler_extension.js.map +0 -1
- package/crawlers/crawler_utils.d.ts.map +0 -1
- package/crawlers/crawler_utils.js.map +0 -1
- package/crawlers/error_snapshotter.d.ts.map +0 -1
- package/crawlers/error_snapshotter.js.map +0 -1
- package/crawlers/error_tracker.d.ts.map +0 -1
- package/crawlers/error_tracker.js.map +0 -1
- package/crawlers/index.d.ts.map +0 -1
- package/crawlers/index.js.map +0 -1
- package/crawlers/statistics.d.ts.map +0 -1
- package/crawlers/statistics.js.map +0 -1
- package/enqueue_links/enqueue_links.d.ts.map +0 -1
- package/enqueue_links/enqueue_links.js.map +0 -1
- package/enqueue_links/index.d.ts.map +0 -1
- package/enqueue_links/index.js.map +0 -1
- package/enqueue_links/shared.d.ts.map +0 -1
- package/enqueue_links/shared.js.map +0 -1
- package/errors.d.ts.map +0 -1
- package/errors.js.map +0 -1
- package/events/event_manager.d.ts.map +0 -1
- package/events/event_manager.js.map +0 -1
- package/events/index.d.ts.map +0 -1
- package/events/index.js.map +0 -1
- package/events/local_event_manager.d.ts.map +0 -1
- package/events/local_event_manager.js.map +0 -1
- package/http_clients/base-http-client.d.ts +0 -134
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -33
- package/http_clients/base-http-client.js.map +0 -1
- package/http_clients/form-data-like.d.ts +0 -67
- package/http_clients/form-data-like.d.ts.map +0 -1
- package/http_clients/form-data-like.js +0 -5
- package/http_clients/form-data-like.js.map +0 -1
- package/http_clients/got-scraping-http-client.d.ts +0 -15
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -69
- package/http_clients/got-scraping-http-client.js.map +0 -1
- package/http_clients/index.d.ts +0 -3
- package/http_clients/index.d.ts.map +0 -1
- package/http_clients/index.js +0 -3
- package/http_clients/index.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/log.d.ts.map +0 -1
- package/log.js.map +0 -1
- package/proxy_configuration.d.ts.map +0 -1
- package/proxy_configuration.js.map +0 -1
- package/request.d.ts.map +0 -1
- package/request.js.map +0 -1
- package/router.d.ts.map +0 -1
- package/router.js.map +0 -1
- package/serialization.d.ts.map +0 -1
- package/serialization.js.map +0 -1
- package/session_pool/consts.d.ts.map +0 -1
- package/session_pool/consts.js.map +0 -1
- package/session_pool/errors.d.ts.map +0 -1
- package/session_pool/errors.js.map +0 -1
- package/session_pool/events.d.ts +0 -3
- package/session_pool/events.d.ts.map +0 -1
- package/session_pool/events.js +0 -3
- package/session_pool/events.js.map +0 -1
- package/session_pool/index.d.ts.map +0 -1
- package/session_pool/index.js.map +0 -1
- package/session_pool/session.d.ts.map +0 -1
- package/session_pool/session.js.map +0 -1
- package/session_pool/session_pool.d.ts.map +0 -1
- package/session_pool/session_pool.js.map +0 -1
- package/storages/access_checking.d.ts.map +0 -1
- package/storages/access_checking.js.map +0 -1
- package/storages/dataset.d.ts.map +0 -1
- package/storages/dataset.js.map +0 -1
- package/storages/index.d.ts.map +0 -1
- package/storages/index.js.map +0 -1
- package/storages/key_value_store.d.ts.map +0 -1
- package/storages/key_value_store.js.map +0 -1
- package/storages/request_list.d.ts.map +0 -1
- package/storages/request_list.js.map +0 -1
- package/storages/request_provider.d.ts +0 -307
- package/storages/request_provider.d.ts.map +0 -1
- package/storages/request_provider.js +0 -555
- package/storages/request_provider.js.map +0 -1
- package/storages/request_queue.d.ts.map +0 -1
- package/storages/request_queue.js.map +0 -1
- package/storages/request_queue_v2.d.ts +0 -87
- package/storages/request_queue_v2.d.ts.map +0 -1
- package/storages/request_queue_v2.js +0 -438
- package/storages/request_queue_v2.js.map +0 -1
- package/storages/sitemap_request_list.d.ts.map +0 -1
- package/storages/sitemap_request_list.js.map +0 -1
- package/storages/storage_manager.d.ts +0 -58
- package/storages/storage_manager.d.ts.map +0 -1
- package/storages/storage_manager.js +0 -105
- package/storages/storage_manager.js.map +0 -1
- package/storages/utils.d.ts.map +0 -1
- package/storages/utils.js.map +0 -1
- package/tsconfig.build.tsbuildinfo +0 -1
- package/typedefs.d.ts.map +0 -1
- package/typedefs.js.map +0 -1
- package/validators.d.ts.map +0 -1
- package/validators.js.map +0 -1
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { getCgroupsVersion } from './runtime.js';
|
|
5
|
+
const CPU_FILE_PATHS = {
|
|
6
|
+
STAT: {
|
|
7
|
+
V1: '/sys/fs/cgroup/cpuacct/cpuacct.usage',
|
|
8
|
+
V2: '/sys/fs/cgroup/cpu.stat',
|
|
9
|
+
},
|
|
10
|
+
QUOTA: {
|
|
11
|
+
V1: '/sys/fs/cgroup/cpu/cpu.cfs_quota_us',
|
|
12
|
+
V2: '/sys/fs/cgroup/cpu.max',
|
|
13
|
+
},
|
|
14
|
+
PERIOD: {
|
|
15
|
+
V1: '/sys/fs/cgroup/cpu/cpu.cfs_period_us',
|
|
16
|
+
V2: '/sys/fs/cgroup/cpu.max',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
let CLOCK_TICKS_PER_SECOND = 100;
|
|
20
|
+
let CLOCK_TICKS_CHECKED = false;
|
|
21
|
+
const NANOSECONDS_PER_SECOND = 1e9;
|
|
22
|
+
const previousTicks = { idle: 0, total: 0 };
|
|
23
|
+
/**
|
|
24
|
+
* Gets the "bare metal" cpu load.
|
|
25
|
+
* Used in
|
|
26
|
+
* - AWS Lambda
|
|
27
|
+
* - Containers without a cGroup quota
|
|
28
|
+
* - Uncontainerized environments
|
|
29
|
+
* @returns a number between 0 and 1 for the cpu load
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export function getCurrentCpuTicks() {
|
|
33
|
+
const cpusCores = os.cpus();
|
|
34
|
+
const ticks = cpusCores.reduce((acc, cpu) => {
|
|
35
|
+
const cpuTimes = Object.values(cpu.times);
|
|
36
|
+
return {
|
|
37
|
+
idle: acc.idle + cpu.times.idle,
|
|
38
|
+
total: acc.total + cpuTimes.reduce((sum, num) => sum + num),
|
|
39
|
+
};
|
|
40
|
+
}, { idle: 0, total: 0 });
|
|
41
|
+
const idleTicksDelta = ticks.idle - previousTicks.idle;
|
|
42
|
+
const totalTicksDelta = ticks.total - previousTicks.total;
|
|
43
|
+
Object.assign(previousTicks, ticks);
|
|
44
|
+
return totalTicksDelta ? 1 - idleTicksDelta / totalTicksDelta : 0;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Reads the linux tick rate.
|
|
48
|
+
* @returns the number of ticks per second, or `null` if detection failed
|
|
49
|
+
*/
|
|
50
|
+
function getClockTicks() {
|
|
51
|
+
try {
|
|
52
|
+
return parseInt(execSync('getconf CLK_TCK').toString().trim(), 10);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads the cgroup cpu quota.
|
|
60
|
+
* In V1, a quota of -1 means “unlimited.”
|
|
61
|
+
* In V2, a first field of "max" means unlimited.
|
|
62
|
+
* @param cgroupsVersion the cGroup version
|
|
63
|
+
* @returns The Cpu Quota
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
export async function getCpuQuota(cgroupsVersion) {
|
|
67
|
+
if (cgroupsVersion === 'V1') {
|
|
68
|
+
const quotaStr = await readFile(CPU_FILE_PATHS.QUOTA.V1, 'utf8');
|
|
69
|
+
const quota = parseInt(quotaStr.trim(), 10);
|
|
70
|
+
return quota === -1 ? null : quota;
|
|
71
|
+
}
|
|
72
|
+
// cgroup v2
|
|
73
|
+
const maxStr = await readFile(CPU_FILE_PATHS.QUOTA.V2, 'utf8');
|
|
74
|
+
const parts = maxStr.trim().split(/\s+/);
|
|
75
|
+
if (parts[0] === 'max') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return parseInt(parts[0], 10);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Reads the cgroup cpu period.
|
|
82
|
+
* @param cgroupsVersion the cGroup version
|
|
83
|
+
* @returns The Cpu quota period
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export async function getCpuPeriod(cgroupsVersion) {
|
|
87
|
+
if (cgroupsVersion === 'V1') {
|
|
88
|
+
const quotaStr = await readFile(CPU_FILE_PATHS.PERIOD.V1, 'utf8');
|
|
89
|
+
const quota = parseInt(quotaStr.trim(), 10);
|
|
90
|
+
return quota;
|
|
91
|
+
}
|
|
92
|
+
// cgroup v2
|
|
93
|
+
const maxStr = await readFile(CPU_FILE_PATHS.PERIOD.V2, 'utf8');
|
|
94
|
+
const parts = maxStr.trim().split(/\s+/);
|
|
95
|
+
return parseInt(parts[1], 10);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Reads the cgroup cpu usage of the container
|
|
99
|
+
*
|
|
100
|
+
* @param cgroupsVersion the cGroup version
|
|
101
|
+
* @returns the cpu usage
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export async function getContainerCpuUsage(cgroupsVersion) {
|
|
105
|
+
if (cgroupsVersion === 'V1') {
|
|
106
|
+
const data = await readFile(CPU_FILE_PATHS.STAT.V1, 'utf8');
|
|
107
|
+
return Number(data.trim());
|
|
108
|
+
}
|
|
109
|
+
// cgroup v2
|
|
110
|
+
const data = await readFile(CPU_FILE_PATHS.STAT.V2, 'utf8');
|
|
111
|
+
const lines = data.split('\n');
|
|
112
|
+
let usageUsec = 0;
|
|
113
|
+
for (const line of lines) {
|
|
114
|
+
const parts = line.trim().split(/\s+/);
|
|
115
|
+
if (parts[0] === 'usage_usec') {
|
|
116
|
+
usageUsec = Number(parts[1]);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Convert microseconds to nanoseconds.
|
|
121
|
+
return usageUsec * 1000;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Reads the cgroup cpu usage of the system from cgroup
|
|
125
|
+
*
|
|
126
|
+
* @returns the cpu usage
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
export async function getSystemCpuUsage() {
|
|
130
|
+
const statData = await readFile('/proc/stat', 'utf8');
|
|
131
|
+
const lines = statData.split('\n');
|
|
132
|
+
for (const line of lines) {
|
|
133
|
+
if (line.startsWith('cpu ')) {
|
|
134
|
+
// Split the line and extract the first seven numeric fields:
|
|
135
|
+
// user, nice, system, idle, iowait, irq, softirq
|
|
136
|
+
const parts = line.split(/\s+/).slice(1, 8);
|
|
137
|
+
let totalTicks = 0;
|
|
138
|
+
for (const part of parts) {
|
|
139
|
+
totalTicks += Number(part);
|
|
140
|
+
}
|
|
141
|
+
// Convert clock ticks to nanoseconds.
|
|
142
|
+
return (totalTicks * NANOSECONDS_PER_SECOND) / CLOCK_TICKS_PER_SECOND;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
throw new Error('no cpu line'); // shouldnt ever happen
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Takes a CPU usage sample for both the container and the system.
|
|
149
|
+
*
|
|
150
|
+
* @returns An object containing the container and system CPU usage.
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
export async function sampleCpuUsage(cGroupsVersion) {
|
|
154
|
+
const [containerUsage, systemUsage] = await Promise.all([
|
|
155
|
+
getContainerCpuUsage(cGroupsVersion),
|
|
156
|
+
getSystemCpuUsage(),
|
|
157
|
+
]);
|
|
158
|
+
return { containerUsage, systemUsage };
|
|
159
|
+
}
|
|
160
|
+
let previousSample = { containerUsage: 0, systemUsage: 0 };
|
|
161
|
+
/**
|
|
162
|
+
* Gets the cpu usage of the system.
|
|
163
|
+
* If the crawler is running in a containerized environment, crawlee will check for a cgroup enforced cpu limit.
|
|
164
|
+
* If a cgroup limit is found, it will be taken as the maximum load against which the current load will be gauged.
|
|
165
|
+
* @returns a number between 0 and 1 for the cpu load
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
export async function getCurrentCpuTicksV2(options = {}) {
|
|
169
|
+
const { containerized = false, logger } = options;
|
|
170
|
+
try {
|
|
171
|
+
// if not containerized
|
|
172
|
+
if (!containerized) {
|
|
173
|
+
// bare metal cpu limit
|
|
174
|
+
return getCurrentCpuTicks();
|
|
175
|
+
}
|
|
176
|
+
if (!CLOCK_TICKS_CHECKED) {
|
|
177
|
+
const ticks = getClockTicks();
|
|
178
|
+
if (ticks === null) {
|
|
179
|
+
CLOCK_TICKS_PER_SECOND = 100;
|
|
180
|
+
logger?.warning('Failed to get clock ticks; defaulting to 100. CPU metrics may be inaccurate.');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
CLOCK_TICKS_PER_SECOND = ticks;
|
|
184
|
+
}
|
|
185
|
+
CLOCK_TICKS_CHECKED = true;
|
|
186
|
+
}
|
|
187
|
+
const cgroupsVersion = await getCgroupsVersion();
|
|
188
|
+
// if cgroup is not detected, return bare metal cpu limit
|
|
189
|
+
if (cgroupsVersion === null) {
|
|
190
|
+
logger?.warningOnce('Your environment is containerized, but your system does not support cgroups.\n' +
|
|
191
|
+
"If you're running containers with limited cpu, cpu auto-scaling will not work properly.");
|
|
192
|
+
return getCurrentCpuTicks();
|
|
193
|
+
}
|
|
194
|
+
// cgroup aware cpu limit. If no limits are set, default to returning getCurrentCpuTicks.
|
|
195
|
+
const quota = await getCpuQuota(cgroupsVersion);
|
|
196
|
+
if (quota === null) {
|
|
197
|
+
// no cgroup limit, return host cpu load
|
|
198
|
+
return getCurrentCpuTicks();
|
|
199
|
+
}
|
|
200
|
+
const period = await getCpuPeriod(cgroupsVersion);
|
|
201
|
+
// eg. having a 200000us quots per 100000us means the cGroup can fully use 2 cores
|
|
202
|
+
const cpuAllowance = quota / period;
|
|
203
|
+
const sample = await sampleCpuUsage(cgroupsVersion);
|
|
204
|
+
const containerDelta = sample.containerUsage - previousSample.containerUsage;
|
|
205
|
+
const systemDelta = sample.systemUsage - previousSample.systemUsage;
|
|
206
|
+
previousSample = sample;
|
|
207
|
+
const numCpus = os.cpus().length;
|
|
208
|
+
// Calculate the CPU usage percentage.
|
|
209
|
+
return ((containerDelta / systemDelta) * numCpus) / cpuAllowance;
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
// if anything fails, default to bare metal metrics
|
|
213
|
+
logger?.warning('Cpu snapshot failed, falling back to bare-metal metrics.', { error: err });
|
|
214
|
+
return getCurrentCpuTicks();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CrawleeLogger } from '@crawlee/types';
|
|
2
|
+
/**
|
|
3
|
+
* Describes memory usage of the process.
|
|
4
|
+
*/
|
|
5
|
+
export interface MemoryInfo {
|
|
6
|
+
/** Total memory available in the system or container */
|
|
7
|
+
totalBytes: number;
|
|
8
|
+
/** Amount of free memory in the system or container */
|
|
9
|
+
freeBytes: number;
|
|
10
|
+
/** Amount of memory used (= totalBytes - freeBytes) */
|
|
11
|
+
usedBytes: number;
|
|
12
|
+
/** Amount of memory used the current Node.js process */
|
|
13
|
+
mainProcessBytes: number;
|
|
14
|
+
/** Amount of memory used by child processes of the current Node.js process */
|
|
15
|
+
childProcessesBytes: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns memory statistics of the process and the system, see {@link MemoryInfo}.
|
|
19
|
+
*
|
|
20
|
+
* If the process runs inside of a container, the `getMemoryInfo` gets container memory limits,
|
|
21
|
+
* otherwise it gets system memory limits.
|
|
22
|
+
*
|
|
23
|
+
* Beware that the function is quite inefficient because it spawns a new process.
|
|
24
|
+
* Therefore you shouldn't call it too often, like more than once per second.
|
|
25
|
+
* @returns An object containing the free and used memory metrics.
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export declare function getMemoryInfo(options?: {
|
|
29
|
+
containerized?: boolean;
|
|
30
|
+
logger?: CrawleeLogger;
|
|
31
|
+
}): Promise<MemoryInfo>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { freemem, totalmem } from 'node:os';
|
|
4
|
+
import { getCgroupsVersion, isLambda } from './runtime.js';
|
|
5
|
+
import { psTree } from './ps-tree.js';
|
|
6
|
+
const MEMORY_FILE_PATHS = {
|
|
7
|
+
TOTAL: {
|
|
8
|
+
V1: '/sys/fs/cgroup/memory/memory.limit_in_bytes',
|
|
9
|
+
V2: '/sys/fs/cgroup/memory.max',
|
|
10
|
+
},
|
|
11
|
+
USED: {
|
|
12
|
+
V1: '/sys/fs/cgroup/memory/memory.usage_in_bytes',
|
|
13
|
+
V2: '/sys/fs/cgroup/memory.current',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Returns memory statistics of the process and the system, see {@link MemoryInfo}.
|
|
18
|
+
*
|
|
19
|
+
* If the process runs inside of a container, the `getMemoryInfo` gets container memory limits,
|
|
20
|
+
* otherwise it gets system memory limits.
|
|
21
|
+
*
|
|
22
|
+
* Beware that the function is quite inefficient because it spawns a new process.
|
|
23
|
+
* Therefore you shouldn't call it too often, like more than once per second.
|
|
24
|
+
* @returns An object containing the free and used memory metrics.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export async function getMemoryInfo(options = {}) {
|
|
28
|
+
const { containerized = false, logger } = options;
|
|
29
|
+
let mainProcessBytes = -1;
|
|
30
|
+
let childProcessesBytes = 0;
|
|
31
|
+
// lambda does *not* have `ps` and other command line tools
|
|
32
|
+
// required to extract memory usage.
|
|
33
|
+
if (isLambda()) {
|
|
34
|
+
// reported in bytes
|
|
35
|
+
mainProcessBytes = process.memoryUsage().rss;
|
|
36
|
+
// https://stackoverflow.com/a/55914335/129415
|
|
37
|
+
const memInfo = execSync('cat /proc/meminfo').toString();
|
|
38
|
+
const values = memInfo.split(/[\n: ]/).filter((val) => val.trim());
|
|
39
|
+
// /proc/meminfo reports in kb, not bytes, the total used memory is reported by meminfo
|
|
40
|
+
// subtract memory used by the main node process in order to infer memory used by any child processes
|
|
41
|
+
childProcessesBytes = +values[19] * 1000 - mainProcessBytes;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Query both root and child processes
|
|
45
|
+
const processes = await psTree(process.pid, true);
|
|
46
|
+
processes.forEach((rec) => {
|
|
47
|
+
// Obtain main process' memory separately
|
|
48
|
+
if (rec.PID === `${process.pid}`) {
|
|
49
|
+
mainProcessBytes = rec.RSS;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
childProcessesBytes += rec.RSS;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
let totalBytes;
|
|
56
|
+
let usedBytes;
|
|
57
|
+
let freeBytes;
|
|
58
|
+
if (isLambda()) {
|
|
59
|
+
// memory size is defined in megabytes
|
|
60
|
+
totalBytes = parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE, 10) * 1000000;
|
|
61
|
+
usedBytes = mainProcessBytes + childProcessesBytes;
|
|
62
|
+
freeBytes = totalBytes - usedBytes;
|
|
63
|
+
}
|
|
64
|
+
else if (containerized) {
|
|
65
|
+
// When running inside a container, use container memory limits
|
|
66
|
+
const cgroupsVersion = await getCgroupsVersion();
|
|
67
|
+
try {
|
|
68
|
+
if (cgroupsVersion === null) {
|
|
69
|
+
throw new Error('cgroup not available');
|
|
70
|
+
}
|
|
71
|
+
let [totalBytesStr, usedBytesStr] = await Promise.all([
|
|
72
|
+
readFile(MEMORY_FILE_PATHS.TOTAL[cgroupsVersion], 'utf8'),
|
|
73
|
+
readFile(MEMORY_FILE_PATHS.USED[cgroupsVersion], 'utf8'),
|
|
74
|
+
]);
|
|
75
|
+
// Cgroups V2 files contains newline character. Getting rid of it for better handling in later part of the code.
|
|
76
|
+
totalBytesStr = totalBytesStr.replace(/[^a-zA-Z0-9 ]/g, '');
|
|
77
|
+
usedBytesStr = usedBytesStr.replace(/[^a-zA-Z0-9 ]/g, '');
|
|
78
|
+
// Cgroups V2 contains 'max' string if memory is not limited
|
|
79
|
+
// See https://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git/tree/Documentation/admin-guide/cgroup-v2.rst (see "memory.max")
|
|
80
|
+
if (totalBytesStr === 'max') {
|
|
81
|
+
totalBytes = totalmem();
|
|
82
|
+
// Cgroups V1 is set to number related to platform and page size if memory is not limited
|
|
83
|
+
// See https://unix.stackexchange.com/q/420906
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
totalBytes = parseInt(totalBytesStr, 10);
|
|
87
|
+
const containerRunsWithUnlimitedMemory = totalBytes > Number.MAX_SAFE_INTEGER;
|
|
88
|
+
if (containerRunsWithUnlimitedMemory)
|
|
89
|
+
totalBytes = totalmem();
|
|
90
|
+
}
|
|
91
|
+
usedBytes = parseInt(usedBytesStr, 10);
|
|
92
|
+
freeBytes = totalBytes - usedBytes;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
logger?.warningOnce('Your environment is containerized, but your system does not support memory cgroups. ' +
|
|
96
|
+
"If you're running containers with limited memory, memory auto-scaling will not work properly.\n\n" +
|
|
97
|
+
`Cause: ${err.message}`);
|
|
98
|
+
totalBytes = totalmem();
|
|
99
|
+
freeBytes = freemem();
|
|
100
|
+
usedBytes = totalBytes - freeBytes;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
totalBytes = totalmem();
|
|
105
|
+
freeBytes = freemem();
|
|
106
|
+
usedBytes = totalBytes - freeBytes;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
totalBytes,
|
|
110
|
+
freeBytes,
|
|
111
|
+
usedBytes,
|
|
112
|
+
mainProcessBytes,
|
|
113
|
+
childProcessesBytes,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ProcessInfo {
|
|
2
|
+
PPID: string;
|
|
3
|
+
PID: string;
|
|
4
|
+
STAT: string | null;
|
|
5
|
+
RSS: number;
|
|
6
|
+
COMMAND: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns a promise that resolves with an array of ProcessInfo objects representing
|
|
10
|
+
* the children of the given PID.
|
|
11
|
+
*
|
|
12
|
+
* @param pid - The PID (number or string) for which to list child processes.
|
|
13
|
+
* @param includeRoot - Optional flag. When true, include the process with the given PID if found.
|
|
14
|
+
* Defaults to false.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare function psTree(pid: number | string, includeRoot?: boolean): Promise<ProcessInfo[]>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import * as readline from 'node:readline';
|
|
3
|
+
/**
|
|
4
|
+
* Returns a promise that resolves with an array of ProcessInfo objects representing
|
|
5
|
+
* the children of the given PID.
|
|
6
|
+
*
|
|
7
|
+
* @param pid - The PID (number or string) for which to list child processes.
|
|
8
|
+
* @param includeRoot - Optional flag. When true, include the process with the given PID if found.
|
|
9
|
+
* Defaults to false.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export async function psTree(pid, includeRoot = false) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
if (typeof pid === 'number') {
|
|
15
|
+
pid = pid.toString();
|
|
16
|
+
}
|
|
17
|
+
let processLister;
|
|
18
|
+
if (process.platform === 'win32') {
|
|
19
|
+
processLister = spawn('powershell', [
|
|
20
|
+
'-NoProfile',
|
|
21
|
+
'-Command',
|
|
22
|
+
'Get-CimInstance Win32_Process | Format-Table ProcessId,ParentProcessId,WorkingSetSize,Name',
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
processLister = spawn('ps', ['-A', '-o', 'ppid,pid,stat,rss,comm']);
|
|
27
|
+
}
|
|
28
|
+
processLister.on('error', reject);
|
|
29
|
+
if (!processLister.stdout) {
|
|
30
|
+
reject(new Error('Child process stdout is null'));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Create a readline interface to process stdout line-by-line.
|
|
34
|
+
const rl = readline.createInterface({
|
|
35
|
+
input: processLister.stdout,
|
|
36
|
+
});
|
|
37
|
+
const rows = [];
|
|
38
|
+
let headers = null;
|
|
39
|
+
rl.on('line', (line) => {
|
|
40
|
+
const trimmed = line.trim();
|
|
41
|
+
if (trimmed === '') {
|
|
42
|
+
return; // Skip empty lines.
|
|
43
|
+
}
|
|
44
|
+
// When headers have been set, skip a dashed separator line.
|
|
45
|
+
const fields = trimmed.split(/\s+/);
|
|
46
|
+
if (headers !== null && fields.every((field) => /^-+$/.test(field))) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// The first nonempty line is assumed to be the header row.
|
|
50
|
+
if (!headers) {
|
|
51
|
+
headers = fields.map(normalizeHeader);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Copy the fields into an array to process.
|
|
55
|
+
const columns = fields.slice();
|
|
56
|
+
// Build the process row object.
|
|
57
|
+
const row = {};
|
|
58
|
+
const hdrs = headers.slice();
|
|
59
|
+
// For all headers except the last one, assign one column per header.
|
|
60
|
+
// The last header gets all remaining columns joined (in case the command name contains spaces).
|
|
61
|
+
for (const [index, header] of hdrs.entries()) {
|
|
62
|
+
let value;
|
|
63
|
+
if (index === hdrs.length - 1) {
|
|
64
|
+
value = columns.join(' ');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
value = columns.shift();
|
|
68
|
+
}
|
|
69
|
+
if (header === 'RSS') {
|
|
70
|
+
row[header] = Number.parseInt(value, 10);
|
|
71
|
+
if (process.platform !== 'win32') {
|
|
72
|
+
// On Unix like systems, convert RSS (in KB) to bytes.
|
|
73
|
+
row[header] *= 1024;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
row[header] = value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// On Windows, add STAT with a null value for compatibility.
|
|
81
|
+
if (process.platform === 'win32') {
|
|
82
|
+
row.STAT = null;
|
|
83
|
+
}
|
|
84
|
+
rows.push(row);
|
|
85
|
+
});
|
|
86
|
+
rl.on('close', () => {
|
|
87
|
+
const parents = {};
|
|
88
|
+
const children = [];
|
|
89
|
+
// Seed with the provided PID.
|
|
90
|
+
parents[pid] = true;
|
|
91
|
+
// Build the list of child processes.
|
|
92
|
+
rows.forEach((proc) => {
|
|
93
|
+
// Skip the 'ps' or 'powershell' commands used by psTree to query the processes
|
|
94
|
+
if (proc.COMMAND === 'ps' || proc.COMMAND === 'powershell.exe') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (parents[proc.PPID]) {
|
|
98
|
+
parents[proc.PID] = true;
|
|
99
|
+
children.push(proc);
|
|
100
|
+
}
|
|
101
|
+
else if (includeRoot && pid === proc.PID) {
|
|
102
|
+
children.push(proc);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
resolve(children);
|
|
106
|
+
});
|
|
107
|
+
// Also listen for errors on the stdout stream.
|
|
108
|
+
processLister.stdout.on('error', reject);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Normalizes the header names so that the rest of the code can work uniformly.
|
|
113
|
+
*
|
|
114
|
+
* On non‑Windows systems, we only adjust "COMM" to "COMMAND" (e.g. on macOS).
|
|
115
|
+
* On Windows, the headers from Get-CimInstance + Format-Table are:
|
|
116
|
+
*
|
|
117
|
+
* ProcessId, ParentProcessId, WorkingSetSize, Name
|
|
118
|
+
*
|
|
119
|
+
* which are mapped to:
|
|
120
|
+
*
|
|
121
|
+
* PID, PPID, RSS, COMMAND
|
|
122
|
+
*/
|
|
123
|
+
function normalizeHeader(str) {
|
|
124
|
+
if (process.platform !== 'win32') {
|
|
125
|
+
// macOS may output "COMM" instead of "COMMAND"
|
|
126
|
+
if (str === 'COMM')
|
|
127
|
+
return 'COMMAND';
|
|
128
|
+
return str;
|
|
129
|
+
}
|
|
130
|
+
switch (str) {
|
|
131
|
+
case 'Name':
|
|
132
|
+
return 'COMMAND';
|
|
133
|
+
case 'ParentProcessId':
|
|
134
|
+
return 'PPID';
|
|
135
|
+
case 'ProcessId':
|
|
136
|
+
return 'PID';
|
|
137
|
+
case 'Status':
|
|
138
|
+
return 'STAT';
|
|
139
|
+
case 'WorkingSetSize':
|
|
140
|
+
return 'RSS';
|
|
141
|
+
default:
|
|
142
|
+
throw new Error(`Unknown process listing header: ${str}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a `Promise` that resolves to true if the code is running in a Docker container.
|
|
3
|
+
*/
|
|
4
|
+
export declare function isDocker(forceReset?: boolean): Promise<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* Detects if crawlee is running in a containerized environment.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isContainerized(): Promise<boolean>;
|
|
9
|
+
export declare function isLambda(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* gets the cgroup version by checking for a file at /sys/fs/cgroup/memory
|
|
12
|
+
* @returns "V1" or "V2" for the version of cgroup or null if cgroup is not found.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getCgroupsVersion(forceReset?: boolean): Promise<"V1" | "V2" | null>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
let isDockerPromiseCache;
|
|
3
|
+
async function createIsDockerPromise() {
|
|
4
|
+
const promise1 = fs
|
|
5
|
+
.stat('/.dockerenv')
|
|
6
|
+
.then(() => true)
|
|
7
|
+
.catch(() => false);
|
|
8
|
+
const promise2 = fs
|
|
9
|
+
.readFile('/proc/self/cgroup', 'utf8')
|
|
10
|
+
.then((content) => content.includes('docker'))
|
|
11
|
+
.catch(() => false);
|
|
12
|
+
const [result1, result2] = await Promise.all([promise1, promise2]);
|
|
13
|
+
return result1 || result2;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns a `Promise` that resolves to true if the code is running in a Docker container.
|
|
17
|
+
*/
|
|
18
|
+
export async function isDocker(forceReset) {
|
|
19
|
+
// Parameter forceReset is just internal for unit tests.
|
|
20
|
+
if (!isDockerPromiseCache || forceReset)
|
|
21
|
+
isDockerPromiseCache = createIsDockerPromise();
|
|
22
|
+
return isDockerPromiseCache;
|
|
23
|
+
}
|
|
24
|
+
let isContainerizedResult;
|
|
25
|
+
/**
|
|
26
|
+
* Detects if crawlee is running in a containerized environment.
|
|
27
|
+
*/
|
|
28
|
+
export async function isContainerized() {
|
|
29
|
+
// Value is very unlikley to change. Cache the result after the first execution.
|
|
30
|
+
if (isContainerizedResult !== undefined) {
|
|
31
|
+
return isContainerizedResult;
|
|
32
|
+
}
|
|
33
|
+
// return false if running in aws lambda
|
|
34
|
+
if (isLambda()) {
|
|
35
|
+
isContainerizedResult = false;
|
|
36
|
+
return isContainerizedResult;
|
|
37
|
+
}
|
|
38
|
+
const dockerenvCheck = fs
|
|
39
|
+
.stat('/.dockerenv')
|
|
40
|
+
.then(() => true)
|
|
41
|
+
.catch(() => false);
|
|
42
|
+
const cgroupCheck = fs
|
|
43
|
+
.readFile('/proc/self/cgroup', 'utf8')
|
|
44
|
+
.then((content) => content.includes('docker'))
|
|
45
|
+
.catch(() => false);
|
|
46
|
+
const [dockerenvResult, cgroupResult] = await Promise.all([dockerenvCheck, cgroupCheck]);
|
|
47
|
+
isContainerizedResult = dockerenvResult || cgroupResult || !!process.env.KUBERNETES_SERVICE_HOST;
|
|
48
|
+
return isContainerizedResult;
|
|
49
|
+
}
|
|
50
|
+
export function isLambda() {
|
|
51
|
+
return !!process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE;
|
|
52
|
+
}
|
|
53
|
+
let _cgroupsVersion;
|
|
54
|
+
/**
|
|
55
|
+
* gets the cgroup version by checking for a file at /sys/fs/cgroup/memory
|
|
56
|
+
* @returns "V1" or "V2" for the version of cgroup or null if cgroup is not found.
|
|
57
|
+
*/
|
|
58
|
+
export async function getCgroupsVersion(forceReset) {
|
|
59
|
+
// Parameter forceReset is just internal for unit tests.
|
|
60
|
+
if (_cgroupsVersion !== undefined && !forceReset) {
|
|
61
|
+
return _cgroupsVersion;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
// If this directory does not exists, cgroups are not available
|
|
65
|
+
await fs.access('/sys/fs/cgroup/');
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
_cgroupsVersion = null;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
_cgroupsVersion = 'V1';
|
|
72
|
+
try {
|
|
73
|
+
// If this directory does not exists, assume the container is using cgroups V2
|
|
74
|
+
await fs.access('/sys/fs/cgroup/memory/');
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
_cgroupsVersion = 'V2';
|
|
78
|
+
}
|
|
79
|
+
return _cgroupsVersion;
|
|
80
|
+
}
|
package/typedefs.d.ts
CHANGED
|
@@ -6,5 +6,4 @@ export type Awaitable<T> = T | PromiseLike<T>;
|
|
|
6
6
|
export declare function entries<T extends {}>(obj: T): [keyof T, T[keyof T]][];
|
|
7
7
|
/** @ignore */
|
|
8
8
|
export declare function keys<T extends {}>(obj: T): (keyof T)[];
|
|
9
|
-
export
|
|
10
|
-
//# sourceMappingURL=typedefs.d.ts.map
|
|
9
|
+
export type { AllowedHttpMethods } from '@crawlee/types';
|
package/typedefs.js
CHANGED
package/validators.d.ts
CHANGED
|
@@ -17,5 +17,12 @@ export declare const validators: {
|
|
|
17
17
|
validator: boolean;
|
|
18
18
|
message: (label: string) => string;
|
|
19
19
|
};
|
|
20
|
+
browserPool: (value: Dictionary) => {
|
|
21
|
+
validator: boolean;
|
|
22
|
+
message: (label: string) => string;
|
|
23
|
+
};
|
|
24
|
+
sessionPool: (value: Dictionary) => {
|
|
25
|
+
validator: boolean;
|
|
26
|
+
message: (label: string) => string;
|
|
27
|
+
};
|
|
20
28
|
};
|
|
21
|
-
//# sourceMappingURL=validators.d.ts.map
|
package/validators.js
CHANGED
|
@@ -7,8 +7,8 @@ export const validators = {
|
|
|
7
7
|
message: (label) => `Expected argument '${label}' to be a Puppeteer Page, got something else.`,
|
|
8
8
|
}),
|
|
9
9
|
proxyConfiguration: (value) => ({
|
|
10
|
-
validator: ow.isValid(value, ow.object.hasKeys('
|
|
11
|
-
message: (label) => `Expected argument '${label}' to
|
|
10
|
+
validator: ow.isValid(value, ow.object.hasKeys('newProxyInfo')),
|
|
11
|
+
message: (label) => `Expected argument '${label}' to implement the IProxyConfiguration interface (missing 'newProxyInfo'), got something else.`,
|
|
12
12
|
}),
|
|
13
13
|
requestList: (value) => ({
|
|
14
14
|
validator: ow.isValid(value, ow.object.hasKeys('fetchNextRequest', 'persistState')),
|
|
@@ -18,5 +18,12 @@ export const validators = {
|
|
|
18
18
|
validator: ow.isValid(value, ow.object.hasKeys('fetchNextRequest', 'addRequest')),
|
|
19
19
|
message: (label) => `Expected argument '${label}' to be a RequestQueue, got something else.`,
|
|
20
20
|
}),
|
|
21
|
+
browserPool: (value) => ({
|
|
22
|
+
validator: ow.isValid(value, ow.object.hasKeys('newPage', 'closePage', 'extractPageState', 'injectPageState')),
|
|
23
|
+
message: (label) => `Expected argument '${label}' to implement the IBrowserPool interface (missing one of 'newPage', 'closePage', 'extractPageState', 'injectPageState'), got something else.`,
|
|
24
|
+
}),
|
|
25
|
+
sessionPool: (value) => ({
|
|
26
|
+
validator: ow.isValid(value, ow.object.hasKeys('getSession')),
|
|
27
|
+
message: (label) => `Expected argument '${label}' to implement the ISessionPool interface (missing 'getSession'), got something else.`,
|
|
28
|
+
}),
|
|
21
29
|
};
|
|
22
|
-
//# sourceMappingURL=validators.js.map
|