@crawlee/core 4.0.0-beta.99 → 4.0.0-rc.1

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.
Files changed (133) hide show
  1. package/README.md +1 -1
  2. package/configuration.d.ts +16 -47
  3. package/configuration.js +13 -25
  4. package/debug.js +4 -4
  5. package/errors.d.ts +28 -38
  6. package/errors.js +33 -47
  7. package/events/event_manager.d.ts +2 -2
  8. package/events/event_manager.js +7 -6
  9. package/events/index.d.ts +1 -0
  10. package/events/local_event_manager.d.ts +1 -8
  11. package/events/local_event_manager.js +13 -13
  12. package/events/system_info.d.ts +38 -0
  13. package/index.d.ts +2 -8
  14. package/index.js +4 -8
  15. package/internal.d.ts +8 -0
  16. package/internal.js +9 -0
  17. package/log.d.ts +10 -11
  18. package/log.js +52 -20
  19. package/memory-storage/memory-storage.d.ts +15 -18
  20. package/memory-storage/memory-storage.js +80 -58
  21. package/memory-storage/resource-clients/dataset.d.ts +1 -6
  22. package/memory-storage/resource-clients/dataset.js +23 -31
  23. package/memory-storage/resource-clients/key-value-store.d.ts +1 -10
  24. package/memory-storage/resource-clients/key-value-store.js +43 -67
  25. package/memory-storage/resource-clients/request-queue.d.ts +1 -42
  26. package/memory-storage/resource-clients/request-queue.js +109 -117
  27. package/owned_or_injected.d.ts +1 -3
  28. package/owned_or_injected.js +17 -17
  29. package/package.json +17 -20
  30. package/proxy_configuration.d.ts +21 -26
  31. package/proxy_configuration.js +35 -25
  32. package/recoverable_state.d.ts +104 -47
  33. package/recoverable_state.js +199 -74
  34. package/request.d.ts +20 -107
  35. package/request.js +78 -244
  36. package/serialization.js +17 -16
  37. package/service_locator.d.ts +22 -10
  38. package/service_locator.js +59 -48
  39. package/storages/batched_adds.d.ts +37 -0
  40. package/storages/batched_adds.js +73 -0
  41. package/storages/dataset.d.ts +13 -8
  42. package/storages/dataset.js +149 -40
  43. package/storages/index.d.ts +4 -4
  44. package/storages/index.js +2 -4
  45. package/storages/key_value_store.d.ts +16 -35
  46. package/storages/key_value_store.js +223 -110
  47. package/storages/key_value_store_codec.js +6 -11
  48. package/storages/request_dedup_cache.d.ts +1 -4
  49. package/storages/request_dedup_cache.js +15 -15
  50. package/storages/request_list.d.ts +9 -104
  51. package/storages/request_list.js +236 -233
  52. package/storages/request_loader.d.ts +49 -18
  53. package/storages/request_loader.js +36 -1
  54. package/storages/request_manager.d.ts +86 -0
  55. package/storages/request_manager_tandem.d.ts +14 -38
  56. package/storages/request_manager_tandem.js +67 -64
  57. package/storages/request_queue.d.ts +23 -50
  58. package/storages/request_queue.js +371 -226
  59. package/storages/storage_instance_manager.d.ts +2 -4
  60. package/storages/storage_instance_manager.js +21 -21
  61. package/storages/storage_stats.d.ts +1 -1
  62. package/storages/storage_stats.js +4 -4
  63. package/storages/transaction.d.ts +270 -0
  64. package/storages/transaction.js +296 -0
  65. package/storages/utils.d.ts +6 -3
  66. package/storages/utils.js +11 -2
  67. package/system-info/runtime.js +7 -7
  68. package/url.d.ts +9 -0
  69. package/url.js +11 -0
  70. package/validators.d.ts +23 -25
  71. package/validators.js +14 -25
  72. package/autoscaling/autoscaled_pool.d.ts +0 -213
  73. package/autoscaling/autoscaled_pool.js +0 -378
  74. package/autoscaling/client_load_signal.d.ts +0 -59
  75. package/autoscaling/client_load_signal.js +0 -73
  76. package/autoscaling/concurrency_system.d.ts +0 -283
  77. package/autoscaling/concurrency_system.js +0 -350
  78. package/autoscaling/cpu_load_signal.d.ts +0 -44
  79. package/autoscaling/cpu_load_signal.js +0 -46
  80. package/autoscaling/event_loop_load_signal.d.ts +0 -54
  81. package/autoscaling/event_loop_load_signal.js +0 -60
  82. package/autoscaling/index.d.ts +0 -9
  83. package/autoscaling/index.js +0 -9
  84. package/autoscaling/load_signal.d.ts +0 -99
  85. package/autoscaling/load_signal.js +0 -103
  86. package/autoscaling/memory_load_signal.d.ts +0 -56
  87. package/autoscaling/memory_load_signal.js +0 -106
  88. package/autoscaling/snapshotter.d.ts +0 -87
  89. package/autoscaling/snapshotter.js +0 -67
  90. package/autoscaling/system_status.d.ts +0 -161
  91. package/autoscaling/system_status.js +0 -139
  92. package/autoscaling/weighted_avg.d.ts +0 -5
  93. package/autoscaling/weighted_avg.js +0 -14
  94. package/cookie_utils.d.ts +0 -44
  95. package/cookie_utils.js +0 -122
  96. package/crawlers/context_pipeline.d.ts +0 -70
  97. package/crawlers/context_pipeline.js +0 -122
  98. package/crawlers/crawler_commons.d.ts +0 -257
  99. package/crawlers/crawler_commons.js +0 -107
  100. package/crawlers/error_snapshotter.d.ts +0 -59
  101. package/crawlers/error_snapshotter.js +0 -117
  102. package/crawlers/error_tracker.d.ts +0 -54
  103. package/crawlers/error_tracker.js +0 -308
  104. package/crawlers/index.d.ts +0 -5
  105. package/crawlers/index.js +0 -5
  106. package/crawlers/internals/types.d.ts +0 -7
  107. package/crawlers/statistics.d.ts +0 -209
  108. package/crawlers/statistics.js +0 -350
  109. package/enqueue_links/enqueue_links.d.ts +0 -264
  110. package/enqueue_links/enqueue_links.js +0 -271
  111. package/enqueue_links/index.d.ts +0 -2
  112. package/enqueue_links/index.js +0 -2
  113. package/enqueue_links/shared.d.ts +0 -83
  114. package/enqueue_links/shared.js +0 -221
  115. package/router.d.ts +0 -309
  116. package/router.js +0 -309
  117. package/session_pool/consts.d.ts +0 -3
  118. package/session_pool/consts.js +0 -3
  119. package/session_pool/errors.d.ts +0 -7
  120. package/session_pool/errors.js +0 -11
  121. package/session_pool/fingerprint.d.ts +0 -9
  122. package/session_pool/fingerprint.js +0 -30
  123. package/session_pool/index.d.ts +0 -4
  124. package/session_pool/index.js +0 -4
  125. package/session_pool/session.d.ts +0 -161
  126. package/session_pool/session.js +0 -218
  127. package/session_pool/session_pool.d.ts +0 -246
  128. package/session_pool/session_pool.js +0 -386
  129. package/storages/access_checking.d.ts +0 -12
  130. package/storages/access_checking.js +0 -17
  131. package/storages/sitemap_request_loader.d.ts +0 -249
  132. package/storages/sitemap_request_loader.js +0 -432
  133. /package/{crawlers/internals/types.js → events/system_info.js} +0 -0
@@ -1,308 +0,0 @@
1
- import { inspect } from 'node:util';
2
- import { ErrorSnapshotter } from './error_snapshotter.js';
3
- const extractPathFromStackTraceLine = (line) => {
4
- const lastStartingRoundBracketIndex = line.lastIndexOf('(');
5
- if (lastStartingRoundBracketIndex !== -1) {
6
- const closingRoundBracketIndex = line.indexOf(')', lastStartingRoundBracketIndex);
7
- if (closingRoundBracketIndex !== -1) {
8
- return line.slice(lastStartingRoundBracketIndex + 1, closingRoundBracketIndex);
9
- }
10
- }
11
- return line;
12
- };
13
- // https://v8.dev/docs/stack-trace-api#appendix%3A-stack-trace-format
14
- const getPathFromStackTrace = (stack) => {
15
- for (const line of stack) {
16
- const path = extractPathFromStackTraceLine(line);
17
- if (path.startsWith('node:') || path.includes('/node_modules/') || path.includes('\\node_modules\\')) {
18
- continue;
19
- }
20
- return path;
21
- }
22
- return extractPathFromStackTraceLine(stack[0]);
23
- };
24
- const getStackTraceGroup = (error, storage, showFullStack) => {
25
- const stack = error.stack?.split('\n').map((line) => line.trim());
26
- let sliceAt = -1;
27
- if (stack) {
28
- for (let i = 0; i < stack.length; i++) {
29
- if (stack[i].startsWith('at ') || stack[i].startsWith('eval at ')) {
30
- sliceAt = i;
31
- break;
32
- }
33
- }
34
- }
35
- let normalizedStackTrace = null;
36
- if (sliceAt !== -1) {
37
- normalizedStackTrace = showFullStack
38
- ? stack
39
- .slice(sliceAt)
40
- .map((x) => x.trim())
41
- .join('\n')
42
- : getPathFromStackTrace(stack.slice(sliceAt));
43
- }
44
- if (!normalizedStackTrace) {
45
- normalizedStackTrace = 'missing stack trace';
46
- }
47
- if (!(normalizedStackTrace in storage)) {
48
- storage[normalizedStackTrace] = Object.create(null);
49
- }
50
- return storage[normalizedStackTrace];
51
- };
52
- const getErrorCodeGroup = (error, storage) => {
53
- let { code } = error;
54
- if (code === undefined) {
55
- code = 'missing error code';
56
- }
57
- if (!(code in storage)) {
58
- storage[code] = Object.create(null);
59
- }
60
- return storage[String(code)];
61
- };
62
- const getErrorNameGroup = (error, storage) => {
63
- const { name } = error;
64
- if (!(name in storage)) {
65
- storage[name] = Object.create(null);
66
- }
67
- return storage[name];
68
- };
69
- const findBiggestWordIntersection = (a, b) => {
70
- let maxStreak = 0;
71
- let bStreakIndex = -1;
72
- let aStreakIndex = -1;
73
- for (let aIndex = 0; aIndex < a.length; aIndex++) {
74
- let bIndex = -1;
75
- do {
76
- let aWalkIndex = aIndex;
77
- bIndex = b.indexOf(a[aIndex], bIndex + 1);
78
- let bWalkIndex = bIndex;
79
- let streak = 0;
80
- while (aWalkIndex < a.length && bWalkIndex < b.length && b[bWalkIndex++] === a[aWalkIndex++]) {
81
- streak++;
82
- }
83
- if (streak > maxStreak) {
84
- maxStreak = streak;
85
- aStreakIndex = aIndex;
86
- bStreakIndex = bIndex;
87
- }
88
- } while (bIndex !== -1);
89
- }
90
- return {
91
- maxStreak,
92
- aStreakIndex,
93
- bStreakIndex,
94
- };
95
- };
96
- const arrayCount = (array, target) => {
97
- let result = 0;
98
- for (const item of array) {
99
- if (item === target) {
100
- result++;
101
- }
102
- }
103
- return result;
104
- };
105
- const calculatePlaceholder = (a, b) => {
106
- const { maxStreak, aStreakIndex, bStreakIndex } = findBiggestWordIntersection(a, b);
107
- if (maxStreak === 0) {
108
- return ['_'];
109
- }
110
- const leftA = a.slice(0, aStreakIndex);
111
- const leftB = b.slice(0, bStreakIndex);
112
- const rightA = a.slice(aStreakIndex + maxStreak);
113
- const rightB = b.slice(bStreakIndex + maxStreak);
114
- const output = [];
115
- if (leftA.length !== 0 || leftB.length !== 0) {
116
- output.push(...calculatePlaceholder(leftA, leftB));
117
- }
118
- output.push(...a.slice(aStreakIndex, aStreakIndex + maxStreak));
119
- if (rightA.length !== 0 || rightB.length !== 0) {
120
- output.push(...calculatePlaceholder(rightA, rightB));
121
- }
122
- return output;
123
- };
124
- const normalizedCalculatePlaceholder = (a, b) => {
125
- const output = calculatePlaceholder(a, b);
126
- // We can't be too general
127
- if (arrayCount(output, '_') / output.length >= 0.5) {
128
- return ['_'];
129
- }
130
- return output;
131
- };
132
- // Merge A (missing placeholders) into B (can contain placeholders but does not have to)
133
- const mergeMessages = (a, b, storage) => {
134
- const placeholder = normalizedCalculatePlaceholder(a.split(' '), b.split(' ')).join(' ');
135
- if (placeholder === '_') {
136
- return undefined;
137
- }
138
- const count = storage[a].count + storage[b].count;
139
- delete storage[a];
140
- delete storage[b];
141
- storage[placeholder] = Object.assign(Object.create(null), {
142
- count,
143
- });
144
- return placeholder;
145
- };
146
- const getErrorMessageGroup = (error, storage, showFullMessage) => {
147
- let { message } = error;
148
- if (!message) {
149
- try {
150
- message =
151
- typeof error === 'string'
152
- ? error
153
- : `Unknown error message. Received non-error object: ${JSON.stringify(error)}`;
154
- }
155
- catch {
156
- message = `Unknown error message. Received non-error object, and could not stringify it: ${inspect(error, {
157
- depth: 0,
158
- })}`;
159
- }
160
- }
161
- if (!showFullMessage) {
162
- const newLineIndex = message.indexOf('\n');
163
- message = message.slice(0, newLineIndex === -1 ? undefined : newLineIndex);
164
- }
165
- if (!(message in storage)) {
166
- storage[message] = Object.assign(Object.create(null), {
167
- count: 0,
168
- });
169
- // This actually safe, since we Object.create(null) so no prototype pollution can happen.
170
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
171
- for (const existingMessage in storage) {
172
- const newMessage = mergeMessages(message, existingMessage, storage);
173
- if (newMessage) {
174
- message = newMessage;
175
- break;
176
- }
177
- }
178
- }
179
- return storage[message];
180
- };
181
- const increaseCount = (group) => {
182
- if (!('count' in group)) {
183
- // In case users don't want to display error message
184
- group.count = 0;
185
- }
186
- group.count++;
187
- };
188
- /**
189
- * This class tracks errors and computes a summary of information like:
190
- * - where the errors happened
191
- * - what the error names are
192
- * - what the error codes are
193
- * - what is the general error message
194
- *
195
- * This is extremely useful when there are dynamic error messages, such as argument validation.
196
- *
197
- * Since the structure of the `tracker.result` object differs when using different options,
198
- * it's typed as `Record<string, unknown>`. The most deep object has a `count` property, which is a number.
199
- *
200
- * It's possible to get the total amount of errors via the `tracker.total` property.
201
- */
202
- export class ErrorTracker {
203
- #options;
204
- result;
205
- total;
206
- errorSnapshotter;
207
- constructor(options = {}) {
208
- this.#options = {
209
- showErrorCode: true,
210
- showErrorName: true,
211
- showStackTrace: true,
212
- showFullStack: false,
213
- showErrorMessage: true,
214
- showFullMessage: false,
215
- saveErrorSnapshots: false,
216
- ...options,
217
- };
218
- if (this.#options.saveErrorSnapshots) {
219
- this.errorSnapshotter = new ErrorSnapshotter();
220
- }
221
- this.result = Object.create(null);
222
- this.total = 0;
223
- }
224
- updateGroup(error) {
225
- let group = this.result;
226
- if (this.#options.showStackTrace) {
227
- group = getStackTraceGroup(error, group, this.#options.showFullStack);
228
- }
229
- if (this.#options.showErrorCode) {
230
- group = getErrorCodeGroup(error, group);
231
- }
232
- if (this.#options.showErrorName) {
233
- group = getErrorNameGroup(error, group);
234
- }
235
- if (this.#options.showErrorMessage) {
236
- group = getErrorMessageGroup(error, group, this.#options.showFullMessage);
237
- }
238
- increaseCount(group);
239
- return group;
240
- }
241
- add(error) {
242
- this.total++;
243
- this.updateGroup(error);
244
- if (typeof error.cause === 'object' && error.cause !== null) {
245
- this.add(error.cause);
246
- }
247
- }
248
- /**
249
- * This method is async, because it captures a snapshot of the error context.
250
- * We added this new method to avoid breaking changes.
251
- */
252
- async addAsync(error, context) {
253
- this.total++;
254
- const group = this.updateGroup(error);
255
- // Capture a snapshot (screenshot and HTML) on the first occurrence of an error
256
- if (group.count === 1 && context) {
257
- await this.captureSnapshot(group, error, context).catch(() => { });
258
- }
259
- if (typeof error.cause === 'object' && error.cause !== null) {
260
- await this.addAsync(error.cause);
261
- }
262
- }
263
- getUniqueErrorCount() {
264
- let count = 0;
265
- const goDeeper = (group) => {
266
- if ('count' in group) {
267
- count++;
268
- return;
269
- }
270
- // eslint-disable-next-line guard-for-in, no-restricted-syntax
271
- for (const key in group) {
272
- goDeeper(group[key]);
273
- }
274
- };
275
- goDeeper(this.result);
276
- return count;
277
- }
278
- getMostPopularErrors(count) {
279
- const result = [];
280
- const goDeeper = (group, path) => {
281
- if ('count' in group) {
282
- result.push([group.count, path]);
283
- return;
284
- }
285
- // eslint-disable-next-line guard-for-in, no-restricted-syntax
286
- for (const key in group) {
287
- goDeeper(group[key], [...path, key]);
288
- }
289
- };
290
- goDeeper(this.result, []);
291
- return result.sort((a, b) => b[0] - a[0]).slice(0, count);
292
- }
293
- async captureSnapshot(storage, error, context) {
294
- if (!this.errorSnapshotter) {
295
- return;
296
- }
297
- const { screenshotFileUrl, htmlFileUrl } = await this.errorSnapshotter.captureSnapshot(error, context);
298
- storage.firstErrorScreenshotUrl = screenshotFileUrl;
299
- storage.firstErrorHtmlUrl = htmlFileUrl;
300
- }
301
- reset() {
302
- // This actually safe, since we Object.create(null) so no prototype pollution can happen.
303
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
304
- for (const key in this.result) {
305
- delete this.result[key];
306
- }
307
- }
308
- }
@@ -1,5 +0,0 @@
1
- export * from './context_pipeline.js';
2
- export * from './crawler_commons.js';
3
- export * from './statistics.js';
4
- export * from './error_tracker.js';
5
- export * from './error_snapshotter.js';
package/crawlers/index.js DELETED
@@ -1,5 +0,0 @@
1
- export * from './context_pipeline.js';
2
- export * from './crawler_commons.js';
3
- export * from './statistics.js';
4
- export * from './error_tracker.js';
5
- export * from './error_snapshotter.js';
@@ -1,7 +0,0 @@
1
- export interface BrowserPage {
2
- content: () => Promise<string>;
3
- }
4
- export interface SnapshottableProperties {
5
- body?: unknown;
6
- page?: BrowserPage;
7
- }
@@ -1,209 +0,0 @@
1
- import type { CrawleeLogger } from '../log.js';
2
- import { KeyValueStore } from '../storages/key_value_store.js';
3
- import { ErrorTracker } from './error_tracker.js';
4
- /**
5
- * Persistence-related options to control how and when crawler's data gets persisted.
6
- */
7
- export interface PersistenceOptions {
8
- /**
9
- * Use this flag to disable or enable periodic persistence to key value store.
10
- * @default true
11
- */
12
- enable?: boolean;
13
- }
14
- /**
15
- * The statistics class provides an interface to collecting and logging run
16
- * statistics for requests.
17
- *
18
- * All statistic information is saved on key value store
19
- * under the key `CRAWLEE_CRAWLER_STATISTICS_*`, persists between
20
- * migrations and abort/resurrect
21
- *
22
- * @category Crawlers
23
- */
24
- export declare class Statistics {
25
- private static id;
26
- /**
27
- * An error tracker for final retry errors.
28
- */
29
- readonly errorTracker: ErrorTracker;
30
- /**
31
- * An error tracker for retry errors prior to the final retry.
32
- */
33
- readonly errorTrackerRetry: ErrorTracker;
34
- /**
35
- * Statistic instance id.
36
- */
37
- readonly id: string;
38
- /**
39
- * Current statistic state used for doing calculations on {@link Statistics.calculate} calls
40
- */
41
- state: StatisticState;
42
- /**
43
- * Contains the current retries histogram. Index 0 means 0 retries, index 2, 2 retries, and so on
44
- */
45
- readonly requestRetryHistogram: number[];
46
- protected keyValueStore?: KeyValueStore;
47
- protected readonly persistStateKey: string;
48
- private logIntervalMillis;
49
- private logMessage;
50
- private listener;
51
- private requestsInProgress;
52
- private readonly log;
53
- private instanceStart;
54
- private logInterval;
55
- private _events?;
56
- private persistenceOptions;
57
- private get events();
58
- /**
59
- * @internal
60
- */
61
- constructor(options?: StatisticsOptions);
62
- /**
63
- * Set the current statistic instance to pristine values
64
- */
65
- reset(): void;
66
- /**
67
- * @param options - Override the persistence options provided in the constructor
68
- */
69
- resetStore(options?: PersistenceOptions): Promise<void>;
70
- /**
71
- * Increments the status code counter.
72
- */
73
- registerStatusCode(code: number): void;
74
- /**
75
- * Starts a job
76
- * @ignore
77
- */
78
- startJob(id: number | string): void;
79
- /**
80
- * Mark job as finished and sets the state
81
- * @ignore
82
- */
83
- finishJob(id: number | string, retryCount: number): void;
84
- /**
85
- * Mark job as failed and sets the state
86
- * @ignore
87
- */
88
- failJob(id: number | string, retryCount: number): void;
89
- /**
90
- * Discards a started job without affecting the finished/failed counters, e.g. when a request
91
- * turns out to be skipped (robots.txt, enqueue strategy) after `startJob` was already called for it.
92
- * @ignore
93
- */
94
- discardJob(id: number | string): void;
95
- /**
96
- * Calculate the current statistics
97
- */
98
- calculate(): {
99
- requestAvgFailedDurationMillis: number;
100
- requestAvgFinishedDurationMillis: number;
101
- requestsFinishedPerMinute: number;
102
- requestsFailedPerMinute: number;
103
- requestTotalDurationMillis: number;
104
- requestsTotal: number;
105
- crawlerRuntimeMillis: number;
106
- };
107
- /**
108
- * Initializes the key value store for persisting the statistics,
109
- * displaying the current state in predefined intervals
110
- */
111
- startCapturing(): Promise<void>;
112
- /**
113
- * Stops logging and remove event listeners, then persist
114
- */
115
- stopCapturing(): Promise<void>;
116
- private saveRetryCountForJob;
117
- /**
118
- * Persist internal state to the key value store
119
- * @param options - Override the persistence options provided in the constructor
120
- */
121
- persistState(options?: PersistenceOptions): Promise<void>;
122
- /**
123
- * Loads the current statistic from the key value store if any
124
- */
125
- protected maybeLoadStatistics(): Promise<void>;
126
- private teardown;
127
- /**
128
- * Make this class serializable when called with `JSON.stringify(statsInstance)` directly
129
- * or through `keyValueStore.setValue('KEY', statsInstance)`
130
- */
131
- toJSON(): StatisticPersistedState;
132
- }
133
- /**
134
- * Configuration for the {@link Statistics} instance used by the crawler
135
- */
136
- export interface StatisticsOptions {
137
- /**
138
- * Interval in seconds to log the current statistics
139
- * @default 60
140
- */
141
- logIntervalSecs?: number;
142
- /**
143
- * Message to log with the current statistics
144
- * @default 'Statistics'
145
- */
146
- logMessage?: string;
147
- /**
148
- * Parent logger instance, the statistics will create a child logger from this.
149
- * @default crawler.log
150
- */
151
- log?: CrawleeLogger;
152
- /**
153
- * Key value store instance to persist the statistics.
154
- * If not provided, the default one will be used when capturing starts
155
- */
156
- keyValueStore?: KeyValueStore;
157
- /**
158
- * Control how and when to persist the statistics.
159
- */
160
- persistenceOptions?: PersistenceOptions;
161
- /**
162
- * Save HTML snapshot (and a screenshot if possible) when an error occurs.
163
- * @default false
164
- */
165
- saveErrorSnapshots?: boolean;
166
- /**
167
- * A unique identifier for this statistics instance. This ID is used for persistence
168
- * to the key value store, ensuring the same statistics can be loaded after script restarts.
169
- *
170
- * If not provided, an auto-incremented ID will be used for backward compatibility.
171
- * This means statistics may not persist correctly across script restarts
172
- * if crawler creation order changes.
173
- */
174
- id?: string;
175
- }
176
- /**
177
- * Format of the persisted stats
178
- */
179
- export interface StatisticPersistedState extends Omit<StatisticState, 'statsPersistedAt'> {
180
- requestRetryHistogram: number[];
181
- statsId: string;
182
- requestAvgFailedDurationMillis: number;
183
- requestAvgFinishedDurationMillis: number;
184
- requestTotalDurationMillis: number;
185
- requestsTotal: number;
186
- crawlerLastStartTimestamp: number;
187
- statsPersistedAt: string;
188
- }
189
- /**
190
- * Contains the statistics state
191
- */
192
- export interface StatisticState {
193
- requestsFinished: number;
194
- requestsFailed: number;
195
- requestsRetries: number;
196
- requestsFailedPerMinute: number;
197
- requestsFinishedPerMinute: number;
198
- requestMinDurationMillis: number;
199
- requestMaxDurationMillis: number;
200
- requestTotalFailedDurationMillis: number;
201
- requestTotalFinishedDurationMillis: number;
202
- crawlerStartedAt: Date | string | null;
203
- crawlerFinishedAt: Date | string | null;
204
- crawlerRuntimeMillis: number;
205
- statsPersistedAt: Date | string | null;
206
- errors: Record<string, unknown>;
207
- retryErrors: Record<string, unknown>;
208
- requestsWithStatusCode: Record<string, number>;
209
- }