@crawlee/core 4.0.0-beta.8 → 4.0.0-beta.80
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 +5 -6
- package/autoscaling/autoscaled_pool.js +12 -11
- 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 +35 -72
- package/autoscaling/snapshotter.js +78 -181
- package/autoscaling/system_status.d.ts +21 -36
- package/autoscaling/system_status.js +46 -84
- 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 +22 -17
- package/crawlers/statistics.js +30 -26
- 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 +14 -149
- package/proxy_configuration.js +19 -168
- 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 +117 -15
- 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 +35 -73
- package/session_pool/session.js +46 -99
- package/session_pool/session_pool.d.ts +71 -72
- package/session_pool/session_pool.js +111 -100
- 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 +38 -82
- package/storages/request_list.js +65 -41
- 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 +303 -46
- package/storages/request_queue.js +629 -214
- 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 +8 -1
- 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,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-size, direct-mapped cache for `uniqueKey`-based request deduplication.
|
|
3
|
+
*
|
|
4
|
+
* `RequestProvider.requestCache` only remembers the first batch of requests, so repeated
|
|
5
|
+
* `addRequestsBatched()` calls with overlapping URLs re-submit already-enqueued requests
|
|
6
|
+
* (https://github.com/apify/crawlee/issues/3120). This is a separate, cheaper cache we can populate on
|
|
7
|
+
* every batch: a fixed number of slots indexed by a hash of the request's cache key, storing the
|
|
8
|
+
* server-assigned `requestId`. Memory is capped by the slot count regardless of the working set size;
|
|
9
|
+
* a hash collision just overwrites a slot, causing an occasional cache miss (a harmless re-submission)
|
|
10
|
+
* but never a false hit — so a genuinely new request is never dropped.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare class RequestDeduplicationCache {
|
|
15
|
+
private readonly size;
|
|
16
|
+
private keys;
|
|
17
|
+
private ids;
|
|
18
|
+
constructor(size?: number);
|
|
19
|
+
get(cacheKey: string): string | null;
|
|
20
|
+
add(cacheKey: string, requestId: string): void;
|
|
21
|
+
clear(): void;
|
|
22
|
+
private indexOf;
|
|
23
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixed-size, direct-mapped cache for `uniqueKey`-based request deduplication.
|
|
3
|
+
*
|
|
4
|
+
* `RequestProvider.requestCache` only remembers the first batch of requests, so repeated
|
|
5
|
+
* `addRequestsBatched()` calls with overlapping URLs re-submit already-enqueued requests
|
|
6
|
+
* (https://github.com/apify/crawlee/issues/3120). This is a separate, cheaper cache we can populate on
|
|
7
|
+
* every batch: a fixed number of slots indexed by a hash of the request's cache key, storing the
|
|
8
|
+
* server-assigned `requestId`. Memory is capped by the slot count regardless of the working set size;
|
|
9
|
+
* a hash collision just overwrites a slot, causing an occasional cache miss (a harmless re-submission)
|
|
10
|
+
* but never a false hit — so a genuinely new request is never dropped.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export class RequestDeduplicationCache {
|
|
15
|
+
size;
|
|
16
|
+
keys;
|
|
17
|
+
ids;
|
|
18
|
+
// The slot count is the same for every queue, so it's a fixed default rather than a per-consumer option.
|
|
19
|
+
constructor(size = 1_000_000) {
|
|
20
|
+
this.size = size;
|
|
21
|
+
this.keys = new Array(size);
|
|
22
|
+
this.ids = new Array(size);
|
|
23
|
+
}
|
|
24
|
+
get(cacheKey) {
|
|
25
|
+
const index = this.indexOf(cacheKey);
|
|
26
|
+
return this.keys[index] === cacheKey ? this.ids[index] : null;
|
|
27
|
+
}
|
|
28
|
+
add(cacheKey, requestId) {
|
|
29
|
+
const index = this.indexOf(cacheKey);
|
|
30
|
+
this.keys[index] = cacheKey;
|
|
31
|
+
this.ids[index] = requestId;
|
|
32
|
+
}
|
|
33
|
+
clear() {
|
|
34
|
+
this.keys = new Array(this.size);
|
|
35
|
+
this.ids = new Array(this.size);
|
|
36
|
+
}
|
|
37
|
+
// A cheap FNV-1a hash of the cache key — avoids pulling in a dedicated hashing dependency.
|
|
38
|
+
indexOf(cacheKey) {
|
|
39
|
+
/* eslint-disable no-bitwise */
|
|
40
|
+
let hash = 0x811c9dc5;
|
|
41
|
+
for (let i = 0; i < cacheKey.length; i++) {
|
|
42
|
+
hash ^= cacheKey.charCodeAt(i);
|
|
43
|
+
hash = Math.imul(hash, 0x01000193);
|
|
44
|
+
}
|
|
45
|
+
return (hash >>> 0) % this.size;
|
|
46
|
+
/* eslint-enable no-bitwise */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,75 +1,13 @@
|
|
|
1
|
-
import type { Dictionary } from '@crawlee/types';
|
|
2
|
-
import { Configuration } from '../configuration.js';
|
|
1
|
+
import type { BaseHttpClient, Dictionary } from '@crawlee/types';
|
|
2
|
+
import type { Configuration } from '../configuration.js';
|
|
3
3
|
import type { ProxyConfiguration } from '../proxy_configuration.js';
|
|
4
4
|
import { type InternalSource, Request, type RequestOptions, type Source } from '../request.js';
|
|
5
|
+
import type { IRequestLoader } from './request_loader.js';
|
|
6
|
+
import type { IRequestManager } from './request_manager.js';
|
|
5
7
|
/** @internal */
|
|
6
8
|
export declare const STATE_PERSISTENCE_KEY = "REQUEST_LIST_STATE";
|
|
7
9
|
/** @internal */
|
|
8
10
|
export declare const REQUESTS_PERSISTENCE_KEY = "REQUEST_LIST_REQUESTS";
|
|
9
|
-
/**
|
|
10
|
-
* Represents a static list of URLs to crawl.
|
|
11
|
-
*/
|
|
12
|
-
export interface IRequestList {
|
|
13
|
-
/**
|
|
14
|
-
* Returns the total number of unique requests present in the list.
|
|
15
|
-
*/
|
|
16
|
-
length(): number;
|
|
17
|
-
/**
|
|
18
|
-
* Returns `true` if all requests were already handled and there are no more left.
|
|
19
|
-
*/
|
|
20
|
-
isFinished(): Promise<boolean>;
|
|
21
|
-
/**
|
|
22
|
-
* Resolves to `true` if the next call to {@link IRequestList.fetchNextRequest} function
|
|
23
|
-
* would return `null`, otherwise it resolves to `false`.
|
|
24
|
-
* Note that even if the list is empty, there might be some pending requests currently being processed.
|
|
25
|
-
*/
|
|
26
|
-
isEmpty(): Promise<boolean>;
|
|
27
|
-
/**
|
|
28
|
-
* Returns number of handled requests.
|
|
29
|
-
*/
|
|
30
|
-
handledCount(): number;
|
|
31
|
-
/**
|
|
32
|
-
* Persists the current state of the `IRequestList` into the default {@link KeyValueStore}.
|
|
33
|
-
* The state is persisted automatically in regular intervals, but calling this method manually
|
|
34
|
-
* is useful in cases where you want to have the most current state available after you pause
|
|
35
|
-
* or stop fetching its requests. For example after you pause or abort a crawl. Or just before
|
|
36
|
-
* a server migration.
|
|
37
|
-
*/
|
|
38
|
-
persistState(): Promise<void>;
|
|
39
|
-
/**
|
|
40
|
-
* Gets the next {@link Request} to process. First, the function gets a request previously reclaimed
|
|
41
|
-
* using the {@link RequestList.reclaimRequest} function, if there is any.
|
|
42
|
-
* Otherwise it gets the next request from sources.
|
|
43
|
-
*
|
|
44
|
-
* The function's `Promise` resolves to `null` if there are no more
|
|
45
|
-
* requests to process.
|
|
46
|
-
*/
|
|
47
|
-
fetchNextRequest(): Promise<Request | null>;
|
|
48
|
-
/**
|
|
49
|
-
* Gets the next {@link Request} to process. First, the function gets a request previously reclaimed
|
|
50
|
-
* using the {@link RequestList.reclaimRequest} function, if there is any.
|
|
51
|
-
* Otherwise it gets the next request from sources.
|
|
52
|
-
*
|
|
53
|
-
* The function resolves to `null` if there are no more requests to process.
|
|
54
|
-
*
|
|
55
|
-
* Can be used to iterate over the `RequestList` instance in a `for await .. of` loop.
|
|
56
|
-
* Provides an alternative for the repeated use of `fetchNextRequest`.
|
|
57
|
-
*/
|
|
58
|
-
[Symbol.asyncIterator](): AsyncGenerator<Request>;
|
|
59
|
-
/**
|
|
60
|
-
* Reclaims request to the list if its processing failed.
|
|
61
|
-
* The request will become available in the next `this.fetchNextRequest()`.
|
|
62
|
-
*/
|
|
63
|
-
reclaimRequest(request: Request): Promise<void>;
|
|
64
|
-
/**
|
|
65
|
-
* Marks request as handled after successful processing.
|
|
66
|
-
*/
|
|
67
|
-
markRequestHandled(request: Request): Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* @internal
|
|
70
|
-
*/
|
|
71
|
-
inProgress: Set<string>;
|
|
72
|
-
}
|
|
73
11
|
export interface RequestListOptions {
|
|
74
12
|
/**
|
|
75
13
|
* An array of sources of URLs for the {@link RequestList}. It can be either an array of strings,
|
|
@@ -209,6 +147,12 @@ export interface RequestListOptions {
|
|
|
209
147
|
keepDuplicateUrls?: boolean;
|
|
210
148
|
/** @internal */
|
|
211
149
|
config?: Configuration;
|
|
150
|
+
/**
|
|
151
|
+
* The HTTP client to be used to download `requestsFromUrl` URLs.
|
|
152
|
+
*
|
|
153
|
+
* If not specified the `RequestList` will use the default HTTP client.
|
|
154
|
+
*/
|
|
155
|
+
httpClient?: BaseHttpClient;
|
|
212
156
|
}
|
|
213
157
|
/**
|
|
214
158
|
* Represents a static list of URLs to crawl.
|
|
@@ -232,8 +176,8 @@ export interface RequestListOptions {
|
|
|
232
176
|
* > In practical terms, such a combination can be useful when there is a large number of initial URLs,
|
|
233
177
|
* > but more URLs would be added dynamically by the crawler.
|
|
234
178
|
*
|
|
235
|
-
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
236
|
-
* which are in progress
|
|
179
|
+
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
180
|
+
* and which are in progress. The state may be automatically persisted to the default
|
|
237
181
|
* {@link KeyValueStore} by setting the `persistStateKey` option so that if the Node.js process is restarted,
|
|
238
182
|
* the crawling can continue where it left off. The automated persisting is launched upon receiving the `persistState`
|
|
239
183
|
* event that is periodically emitted by {@link EventManager}.
|
|
@@ -271,7 +215,7 @@ export interface RequestListOptions {
|
|
|
271
215
|
* ```
|
|
272
216
|
* @category Sources
|
|
273
217
|
*/
|
|
274
|
-
export declare class RequestList implements
|
|
218
|
+
export declare class RequestList implements IRequestLoader {
|
|
275
219
|
private log;
|
|
276
220
|
/**
|
|
277
221
|
* Array of all requests from all sources, in the order as they appeared in sources.
|
|
@@ -289,10 +233,11 @@ export declare class RequestList implements IRequestList {
|
|
|
289
233
|
*/
|
|
290
234
|
inProgress: Set<string>;
|
|
291
235
|
/**
|
|
292
|
-
*
|
|
236
|
+
* `uniqueKey`s of requests that were in progress when the state was last persisted and thus need to be
|
|
237
|
+
* re-crawled after a restart. They are served before advancing through the rest of the sources.
|
|
293
238
|
* @internal
|
|
294
239
|
*/
|
|
295
|
-
|
|
240
|
+
private requestsToRetry;
|
|
296
241
|
/**
|
|
297
242
|
* Starts as true because until we handle the first request, the list is effectively persisted by doing nothing.
|
|
298
243
|
* @internal
|
|
@@ -313,7 +258,7 @@ export declare class RequestList implements IRequestList {
|
|
|
313
258
|
private sources;
|
|
314
259
|
private sourcesFunction?;
|
|
315
260
|
private proxyConfiguration?;
|
|
316
|
-
private
|
|
261
|
+
private httpClient?;
|
|
317
262
|
/**
|
|
318
263
|
* To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
|
|
319
264
|
* @param options All `RequestList` configuration options
|
|
@@ -342,6 +287,12 @@ export declare class RequestList implements IRequestList {
|
|
|
342
287
|
* @inheritDoc
|
|
343
288
|
*/
|
|
344
289
|
persistState(): Promise<void>;
|
|
290
|
+
/**
|
|
291
|
+
* Removes the `PERSIST_STATE` event listener registered during initialization and persists
|
|
292
|
+
* the current state one last time. Call this when you are done with the `RequestList` to avoid
|
|
293
|
+
* leaking the listener (and the requests it retains) on the shared event manager.
|
|
294
|
+
*/
|
|
295
|
+
teardown(): Promise<void>;
|
|
345
296
|
/**
|
|
346
297
|
* Unlike persistState(), this is used only internally, since the sources
|
|
347
298
|
* are automatically persisted at RequestList initialization (if the persistRequestsKey is set),
|
|
@@ -382,11 +333,7 @@ export declare class RequestList implements IRequestList {
|
|
|
382
333
|
/**
|
|
383
334
|
* @inheritDoc
|
|
384
335
|
*/
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* @inheritDoc
|
|
388
|
-
*/
|
|
389
|
-
reclaimRequest(request: Request): Promise<void>;
|
|
336
|
+
markRequestAsHandled(request: Request): Promise<void>;
|
|
390
337
|
/**
|
|
391
338
|
* Adds all fetched requests from a URL from a remote resource.
|
|
392
339
|
*/
|
|
@@ -408,9 +355,9 @@ export declare class RequestList implements IRequestList {
|
|
|
408
355
|
*/
|
|
409
356
|
protected _ensureUniqueKeyValid(uniqueKey: string): void;
|
|
410
357
|
/**
|
|
411
|
-
* Checks that request is
|
|
358
|
+
* Checks that a request is currently being processed and throws an error if not.
|
|
412
359
|
*/
|
|
413
|
-
protected
|
|
360
|
+
protected _ensureInProgress(uniqueKey: string): void;
|
|
414
361
|
/**
|
|
415
362
|
* Throws an error if request list wasn't initialized.
|
|
416
363
|
*/
|
|
@@ -418,11 +365,21 @@ export declare class RequestList implements IRequestList {
|
|
|
418
365
|
/**
|
|
419
366
|
* Returns the total number of unique requests present in the `RequestList`.
|
|
420
367
|
*/
|
|
421
|
-
|
|
368
|
+
getTotalCount(): Promise<number>;
|
|
369
|
+
/**
|
|
370
|
+
* Returns the number of pending requests in the `RequestList`.
|
|
371
|
+
*/
|
|
372
|
+
getPendingCount(): Promise<number>;
|
|
373
|
+
/**
|
|
374
|
+
* Combines this list with a request manager (a {@link RequestQueue} by default) into a
|
|
375
|
+
* {@link RequestManagerTandem}, allowing requests to be added and reclaimed while still
|
|
376
|
+
* being read from this list first.
|
|
377
|
+
*/
|
|
378
|
+
toTandem(requestManager?: IRequestManager): Promise<IRequestManager>;
|
|
422
379
|
/**
|
|
423
380
|
* @inheritDoc
|
|
424
381
|
*/
|
|
425
|
-
|
|
382
|
+
getHandledCount(): Promise<number>;
|
|
426
383
|
/**
|
|
427
384
|
* Opens a request list and returns a promise resolving to an instance
|
|
428
385
|
* of the {@link RequestList} class that is already initialized.
|
|
@@ -509,4 +466,3 @@ export interface RequestListState {
|
|
|
509
466
|
type RequestListSource = string | Source;
|
|
510
467
|
export type RequestListSourcesFunction = () => Promise<RequestListSource[]>;
|
|
511
468
|
export {};
|
|
512
|
-
//# sourceMappingURL=request_list.d.ts.map
|
package/storages/request_list.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { downloadListOfUrls } from '@crawlee/utils';
|
|
2
2
|
import ow, { ArgumentError } from 'ow';
|
|
3
|
-
import { Configuration } from '../configuration.js';
|
|
4
|
-
import { log } from '../log.js';
|
|
5
3
|
import { Request } from '../request.js';
|
|
6
4
|
import { createDeserialize, serializeArray } from '../serialization.js';
|
|
5
|
+
import { serviceLocator } from '../service_locator.js';
|
|
7
6
|
import { KeyValueStore } from './key_value_store.js';
|
|
8
7
|
import { purgeDefaultStorages } from './utils.js';
|
|
9
8
|
/** @internal */
|
|
@@ -33,8 +32,8 @@ const CONTENT_TYPE_BINARY = 'application/octet-stream';
|
|
|
33
32
|
* > In practical terms, such a combination can be useful when there is a large number of initial URLs,
|
|
34
33
|
* > but more URLs would be added dynamically by the crawler.
|
|
35
34
|
*
|
|
36
|
-
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
37
|
-
* which are in progress
|
|
35
|
+
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
36
|
+
* and which are in progress. The state may be automatically persisted to the default
|
|
38
37
|
* {@link KeyValueStore} by setting the `persistStateKey` option so that if the Node.js process is restarted,
|
|
39
38
|
* the crawling can continue where it left off. The automated persisting is launched upon receiving the `persistState`
|
|
40
39
|
* event that is periodically emitted by {@link EventManager}.
|
|
@@ -73,7 +72,7 @@ const CONTENT_TYPE_BINARY = 'application/octet-stream';
|
|
|
73
72
|
* @category Sources
|
|
74
73
|
*/
|
|
75
74
|
export class RequestList {
|
|
76
|
-
log =
|
|
75
|
+
log = serviceLocator.getLogger().child({ prefix: 'RequestList' });
|
|
77
76
|
/**
|
|
78
77
|
* Array of all requests from all sources, in the order as they appeared in sources.
|
|
79
78
|
* All requests in the array have distinct uniqueKey!
|
|
@@ -90,10 +89,11 @@ export class RequestList {
|
|
|
90
89
|
*/
|
|
91
90
|
inProgress = new Set();
|
|
92
91
|
/**
|
|
93
|
-
*
|
|
92
|
+
* `uniqueKey`s of requests that were in progress when the state was last persisted and thus need to be
|
|
93
|
+
* re-crawled after a restart. They are served before advancing through the rest of the sources.
|
|
94
94
|
* @internal
|
|
95
95
|
*/
|
|
96
|
-
|
|
96
|
+
requestsToRetry = [];
|
|
97
97
|
/**
|
|
98
98
|
* Starts as true because until we handle the first request, the list is effectively persisted by doing nothing.
|
|
99
99
|
* @internal
|
|
@@ -114,14 +114,14 @@ export class RequestList {
|
|
|
114
114
|
sources;
|
|
115
115
|
sourcesFunction;
|
|
116
116
|
proxyConfiguration;
|
|
117
|
-
|
|
117
|
+
httpClient;
|
|
118
118
|
/**
|
|
119
119
|
* To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
|
|
120
120
|
* @param options All `RequestList` configuration options
|
|
121
121
|
* @internal
|
|
122
122
|
*/
|
|
123
123
|
constructor(options = {}) {
|
|
124
|
-
const { sources, sourcesFunction, persistStateKey, persistRequestsKey, state, proxyConfiguration, keepDuplicateUrls = false,
|
|
124
|
+
const { sources, sourcesFunction, persistStateKey, persistRequestsKey, state, proxyConfiguration, keepDuplicateUrls = false, httpClient, } = options;
|
|
125
125
|
if (!(sources || sourcesFunction)) {
|
|
126
126
|
throw new ArgumentError('At least one of "sources" or "sourcesFunction" must be provided.', this.constructor);
|
|
127
127
|
}
|
|
@@ -137,11 +137,12 @@ export class RequestList {
|
|
|
137
137
|
}),
|
|
138
138
|
keepDuplicateUrls: ow.optional.boolean,
|
|
139
139
|
proxyConfiguration: ow.optional.object,
|
|
140
|
+
httpClient: ow.optional.object,
|
|
140
141
|
}));
|
|
141
|
-
this.persistStateKey = persistStateKey ? `
|
|
142
|
-
this.persistRequestsKey = persistRequestsKey ? `
|
|
142
|
+
this.persistStateKey = persistStateKey ? `CRAWLEE_${persistStateKey}` : persistStateKey;
|
|
143
|
+
this.persistRequestsKey = persistRequestsKey ? `CRAWLEE_${persistRequestsKey}` : persistRequestsKey;
|
|
143
144
|
this.initialState = state;
|
|
144
|
-
this.
|
|
145
|
+
this.httpClient = httpClient;
|
|
145
146
|
// If this option is set then all requests will get a pre-generated unique ID and duplicate URLs will be kept in the list.
|
|
146
147
|
this.keepDuplicateUrls = keepDuplicateUrls;
|
|
147
148
|
// Will be empty after initialization to save memory.
|
|
@@ -149,6 +150,7 @@ export class RequestList {
|
|
|
149
150
|
this.sourcesFunction = sourcesFunction;
|
|
150
151
|
// The proxy configuration used for `requestsFromUrl` requests.
|
|
151
152
|
this.proxyConfiguration = proxyConfiguration;
|
|
153
|
+
this.persistState = this.persistState.bind(this);
|
|
152
154
|
}
|
|
153
155
|
/**
|
|
154
156
|
* Loads all remote sources of URLs and potentially starts periodic state persistence.
|
|
@@ -174,7 +176,7 @@ export class RequestList {
|
|
|
174
176
|
if (this.persistRequestsKey && !this.areRequestsPersisted)
|
|
175
177
|
await this._persistRequests();
|
|
176
178
|
if (this.persistStateKey) {
|
|
177
|
-
|
|
179
|
+
serviceLocator.getEventManager().on("persistState" /* EventType.PERSIST_STATE */, this.persistState);
|
|
178
180
|
}
|
|
179
181
|
return this;
|
|
180
182
|
}
|
|
@@ -187,6 +189,7 @@ export class RequestList {
|
|
|
187
189
|
// We don't need the sources so we purge them to
|
|
188
190
|
// prevent them from hanging in memory.
|
|
189
191
|
for (let i = 0; i < this.sources.length; i++) {
|
|
192
|
+
// oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
|
|
190
193
|
delete this.sources[i];
|
|
191
194
|
}
|
|
192
195
|
this.sources = [];
|
|
@@ -209,6 +212,7 @@ export class RequestList {
|
|
|
209
212
|
const source = this.sources[i];
|
|
210
213
|
// Using delete here to drop the original object ASAP to free memory
|
|
211
214
|
// .pop would reverse the array and .shift is SLOW.
|
|
215
|
+
// oxlint-disable-next-line typescript/no-array-delete
|
|
212
216
|
delete this.sources[i];
|
|
213
217
|
if (typeof source === 'object' && source.requestsFromUrl) {
|
|
214
218
|
const fetchedRequests = await this._fetchRequestsFromUrl(source);
|
|
@@ -225,9 +229,12 @@ export class RequestList {
|
|
|
225
229
|
const sourcesFromFunction = await this.sourcesFunction();
|
|
226
230
|
const sourcesFromFunctionCount = sourcesFromFunction.length;
|
|
227
231
|
for (let i = 0; i < sourcesFromFunctionCount; i++) {
|
|
228
|
-
const source = sourcesFromFunction
|
|
232
|
+
const source = sourcesFromFunction[i];
|
|
233
|
+
// oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
|
|
234
|
+
delete sourcesFromFunction[i];
|
|
229
235
|
this._addRequest(source);
|
|
230
236
|
}
|
|
237
|
+
sourcesFromFunction.length = 0;
|
|
231
238
|
}
|
|
232
239
|
catch (e) {
|
|
233
240
|
const err = e;
|
|
@@ -254,6 +261,17 @@ export class RequestList {
|
|
|
254
261
|
this.log.exception(err, 'Attempted to persist state, but failed.');
|
|
255
262
|
}
|
|
256
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Removes the `PERSIST_STATE` event listener registered during initialization and persists
|
|
266
|
+
* the current state one last time. Call this when you are done with the `RequestList` to avoid
|
|
267
|
+
* leaking the listener (and the requests it retains) on the shared event manager.
|
|
268
|
+
*/
|
|
269
|
+
async teardown() {
|
|
270
|
+
serviceLocator.getEventManager().off("persistState" /* EventType.PERSIST_STATE */, this.persistState);
|
|
271
|
+
if (this.persistStateKey) {
|
|
272
|
+
await this.persistState();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
257
275
|
/**
|
|
258
276
|
* Unlike persistState(), this is used only internally, since the sources
|
|
259
277
|
* are automatically persisted at RequestList initialization (if the persistRequestsKey is set),
|
|
@@ -316,8 +334,8 @@ export class RequestList {
|
|
|
316
334
|
this.inProgress.delete(uniqueKey);
|
|
317
335
|
}
|
|
318
336
|
}
|
|
319
|
-
// All in-progress requests need to be re-crawled
|
|
320
|
-
this.
|
|
337
|
+
// All in-progress requests were interrupted and need to be re-crawled.
|
|
338
|
+
this.requestsToRetry = [...this.inProgress];
|
|
321
339
|
}
|
|
322
340
|
/**
|
|
323
341
|
* Attempts to load state and requests using the `RequestList` configuration
|
|
@@ -359,7 +377,7 @@ export class RequestList {
|
|
|
359
377
|
*/
|
|
360
378
|
async isEmpty() {
|
|
361
379
|
this._ensureIsInitialized();
|
|
362
|
-
return this.
|
|
380
|
+
return this.requestsToRetry.length === 0 && this.nextIndex >= this.requests.length;
|
|
363
381
|
}
|
|
364
382
|
/**
|
|
365
383
|
* @inheritDoc
|
|
@@ -373,10 +391,9 @@ export class RequestList {
|
|
|
373
391
|
*/
|
|
374
392
|
async fetchNextRequest() {
|
|
375
393
|
this._ensureIsInitialized();
|
|
376
|
-
// First
|
|
377
|
-
const uniqueKey = this.
|
|
394
|
+
// First re-serve any requests that were interrupted before the last state persist.
|
|
395
|
+
const uniqueKey = this.requestsToRetry.shift();
|
|
378
396
|
if (uniqueKey) {
|
|
379
|
-
this.reclaimed.delete(uniqueKey);
|
|
380
397
|
const index = this.uniqueKeyToIndex[uniqueKey];
|
|
381
398
|
return this.ensureRequest(this.requests[index], index);
|
|
382
399
|
}
|
|
@@ -412,24 +429,14 @@ export class RequestList {
|
|
|
412
429
|
/**
|
|
413
430
|
* @inheritDoc
|
|
414
431
|
*/
|
|
415
|
-
async
|
|
432
|
+
async markRequestAsHandled(request) {
|
|
416
433
|
const { uniqueKey } = request;
|
|
417
434
|
this._ensureUniqueKeyValid(uniqueKey);
|
|
418
|
-
this.
|
|
435
|
+
this._ensureInProgress(uniqueKey);
|
|
419
436
|
this._ensureIsInitialized();
|
|
420
437
|
this.inProgress.delete(uniqueKey);
|
|
421
438
|
this.isStatePersisted = false;
|
|
422
439
|
}
|
|
423
|
-
/**
|
|
424
|
-
* @inheritDoc
|
|
425
|
-
*/
|
|
426
|
-
async reclaimRequest(request) {
|
|
427
|
-
const { uniqueKey } = request;
|
|
428
|
-
this._ensureUniqueKeyValid(uniqueKey);
|
|
429
|
-
this._ensureInProgressAndNotReclaimed(uniqueKey);
|
|
430
|
-
this._ensureIsInitialized();
|
|
431
|
-
this.reclaimed.add(uniqueKey);
|
|
432
|
-
}
|
|
433
440
|
/**
|
|
434
441
|
* Adds all fetched requests from a URL from a remote resource.
|
|
435
442
|
*/
|
|
@@ -524,15 +531,12 @@ export class RequestList {
|
|
|
524
531
|
}
|
|
525
532
|
}
|
|
526
533
|
/**
|
|
527
|
-
* Checks that request is
|
|
534
|
+
* Checks that a request is currently being processed and throws an error if not.
|
|
528
535
|
*/
|
|
529
|
-
|
|
536
|
+
_ensureInProgress(uniqueKey) {
|
|
530
537
|
if (!this.inProgress.has(uniqueKey)) {
|
|
531
538
|
throw new Error(`The request is not being processed (uniqueKey: ${uniqueKey})`);
|
|
532
539
|
}
|
|
533
|
-
if (this.reclaimed.has(uniqueKey)) {
|
|
534
|
-
throw new Error(`The request was already reclaimed (uniqueKey: ${uniqueKey})`);
|
|
535
|
-
}
|
|
536
540
|
}
|
|
537
541
|
/**
|
|
538
542
|
* Throws an error if request list wasn't initialized.
|
|
@@ -545,14 +549,32 @@ export class RequestList {
|
|
|
545
549
|
/**
|
|
546
550
|
* Returns the total number of unique requests present in the `RequestList`.
|
|
547
551
|
*/
|
|
548
|
-
|
|
552
|
+
async getTotalCount() {
|
|
549
553
|
this._ensureIsInitialized();
|
|
550
554
|
return this.requests.length;
|
|
551
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* Returns the number of pending requests in the `RequestList`.
|
|
558
|
+
*/
|
|
559
|
+
async getPendingCount() {
|
|
560
|
+
this._ensureIsInitialized();
|
|
561
|
+
return this.requests.length - (this.nextIndex - this.inProgress.size);
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Combines this list with a request manager (a {@link RequestQueue} by default) into a
|
|
565
|
+
* {@link RequestManagerTandem}, allowing requests to be added and reclaimed while still
|
|
566
|
+
* being read from this list first.
|
|
567
|
+
*/
|
|
568
|
+
async toTandem(requestManager) {
|
|
569
|
+
// Import here to avoid circular imports.
|
|
570
|
+
const { RequestManagerTandem } = await import('./request_manager_tandem.js');
|
|
571
|
+
const { RequestQueue } = await import('./request_queue.js');
|
|
572
|
+
return new RequestManagerTandem(this, requestManager ?? (await RequestQueue.open()));
|
|
573
|
+
}
|
|
552
574
|
/**
|
|
553
575
|
* @inheritDoc
|
|
554
576
|
*/
|
|
555
|
-
|
|
577
|
+
async getHandledCount() {
|
|
556
578
|
this._ensureIsInitialized();
|
|
557
579
|
return this.nextIndex - this.inProgress.size;
|
|
558
580
|
}
|
|
@@ -633,7 +655,9 @@ export class RequestList {
|
|
|
633
655
|
* @internal wraps public utility for mocking purposes
|
|
634
656
|
*/
|
|
635
657
|
async _downloadListOfUrls(options) {
|
|
636
|
-
return downloadListOfUrls(
|
|
658
|
+
return downloadListOfUrls({
|
|
659
|
+
...options,
|
|
660
|
+
httpClient: this.httpClient,
|
|
661
|
+
});
|
|
637
662
|
}
|
|
638
663
|
}
|
|
639
|
-
//# sourceMappingURL=request_list.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Dictionary } from '@crawlee/types';
|
|
2
|
+
import type { Request } from '../request.js';
|
|
3
|
+
import type { IRequestManager } from './request_manager.js';
|
|
4
|
+
import type { RequestQueueOperationInfo } from './request_queue.js';
|
|
5
|
+
/**
|
|
6
|
+
* An abstract interface defining a read-only stream of requests to crawl.
|
|
7
|
+
*
|
|
8
|
+
* Request loaders are used to manage and provide access to a storage of crawling requests.
|
|
9
|
+
*
|
|
10
|
+
* Key responsibilities:
|
|
11
|
+
* - Fetching the next request to be processed.
|
|
12
|
+
* - Marking requests as handled once they are no longer in progress.
|
|
13
|
+
* - Managing state information such as the total and handled request counts.
|
|
14
|
+
*
|
|
15
|
+
* ## Request lifecycle contract
|
|
16
|
+
*
|
|
17
|
+
* Every request returned by {@link IRequestLoader.fetchNextRequest} is considered **in progress**
|
|
18
|
+
* until it is passed to {@link IRequestLoader.markRequestAsHandled}. Once you fetch a request, you are
|
|
19
|
+
* obligated to eventually mark it as handled — there is no way to hand a request back to a loader
|
|
20
|
+
* (only an {@link IRequestManager} can reclaim requests for a retry). "Handled" therefore means
|
|
21
|
+
* "finished with this request", whether processing succeeded or was abandoned after exhausting retries.
|
|
22
|
+
*
|
|
23
|
+
* Honoring this contract matters for three reasons:
|
|
24
|
+
* - **Restarts and migrations:** loaders that persist their state (see {@link IRequestLoader.persistState})
|
|
25
|
+
* treat in-progress requests as interrupted and re-serve them after a restart. A request that is fetched
|
|
26
|
+
* but never marked handled will be crawled again.
|
|
27
|
+
* - **Termination detection:** {@link IRequestLoader.isFinished} only resolves to `true` once nothing is
|
|
28
|
+
* in progress. Leaving a request unmarked keeps the crawler running indefinitely.
|
|
29
|
+
* - **Bookkeeping:** the handled and pending counts are derived from the set of in-progress requests, so
|
|
30
|
+
* skipping {@link IRequestLoader.markRequestAsHandled} corrupts {@link IRequestLoader.getHandledCount}
|
|
31
|
+
* and {@link IRequestLoader.getPendingCount}.
|
|
32
|
+
*
|
|
33
|
+
* Concrete implementations such as {@link RequestList} or {@link SitemapRequestLoader} build on this interface.
|
|
34
|
+
* The {@link IRequestManager} interface extends it with the capability to enqueue and reclaim requests.
|
|
35
|
+
*/
|
|
36
|
+
export interface IRequestLoader {
|
|
37
|
+
/**
|
|
38
|
+
* Returns an approximation of the total number of requests in the loader (i.e. pending + handled).
|
|
39
|
+
*/
|
|
40
|
+
getTotalCount(): Promise<number>;
|
|
41
|
+
/**
|
|
42
|
+
* Returns an approximation of the number of pending requests in the loader.
|
|
43
|
+
*/
|
|
44
|
+
getPendingCount(): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the number of requests in the loader that have been handled.
|
|
47
|
+
*/
|
|
48
|
+
getHandledCount(): Promise<number>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns `true` if all requests were already handled and there are no more left.
|
|
51
|
+
*/
|
|
52
|
+
isFinished(): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolves to `true` if the next call to {@link IRequestLoader.fetchNextRequest} function
|
|
55
|
+
* would return `null`, otherwise it resolves to `false`.
|
|
56
|
+
* Note that even if the loader is empty, there might be some pending requests currently being processed.
|
|
57
|
+
*/
|
|
58
|
+
isEmpty(): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Gets the next {@link Request} to process, or `null` if there are no more pending requests.
|
|
61
|
+
*
|
|
62
|
+
* The returned request is marked as **in progress** and remains so until it is passed to
|
|
63
|
+
* {@link IRequestLoader.markRequestAsHandled}. The caller is responsible for eventually marking
|
|
64
|
+
* every fetched request as handled; otherwise the loader never considers itself finished and the
|
|
65
|
+
* request may be re-served after a restart. See the request lifecycle contract on {@link IRequestLoader}.
|
|
66
|
+
*/
|
|
67
|
+
fetchNextRequest<T extends Dictionary = Dictionary>(): Promise<Request<T> | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Can be used to iterate over the loader instance in a `for await .. of` loop.
|
|
70
|
+
* Provides an alternative for the repeated use of `fetchNextRequest`.
|
|
71
|
+
*/
|
|
72
|
+
[Symbol.asyncIterator](): AsyncGenerator<Request>;
|
|
73
|
+
/**
|
|
74
|
+
* Marks a request previously returned by {@link IRequestLoader.fetchNextRequest} as handled,
|
|
75
|
+
* removing it from the set of in-progress requests.
|
|
76
|
+
*
|
|
77
|
+
* Call this once you are done with the request — whether processing succeeded or was abandoned after
|
|
78
|
+
* exhausting retries. Because a loader cannot take a request back, marking it handled is the only way to
|
|
79
|
+
* signal completion; failing to do so prevents {@link IRequestLoader.isFinished} from ever resolving to
|
|
80
|
+
* `true` and skews the handled and pending counts. See the request lifecycle contract on {@link IRequestLoader}.
|
|
81
|
+
*/
|
|
82
|
+
markRequestAsHandled(request: Request): Promise<RequestQueueOperationInfo | void | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Persists the current state of the loader into the default {@link KeyValueStore}.
|
|
85
|
+
*
|
|
86
|
+
* Not all loaders support persistence; implementations that do not should leave this `undefined`.
|
|
87
|
+
*/
|
|
88
|
+
persistState?(): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Combines the loader with a request manager to support adding and reclaiming requests.
|
|
91
|
+
*
|
|
92
|
+
* @param requestManager Request manager to combine the loader with. If not provided, the default
|
|
93
|
+
* {@link RequestQueue} is used.
|
|
94
|
+
*/
|
|
95
|
+
toTandem?(requestManager?: IRequestManager): Promise<IRequestManager>;
|
|
96
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Request, Source } from '../request.js';
|
|
2
|
+
import type { IRequestLoader } from './request_loader.js';
|
|
3
|
+
import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, RequestQueueOperationInfo, RequestQueueOperationOptions } from './request_queue.js';
|
|
4
|
+
export type RequestsLike = AsyncIterable<Source | string> | Iterable<Source | string> | (Source | string)[];
|
|
5
|
+
/**
|
|
6
|
+
* Extends the read-only {@link IRequestLoader} interface with the capability to enqueue new requests
|
|
7
|
+
* and reclaim failed ones.
|
|
8
|
+
*/
|
|
9
|
+
export interface IRequestManager extends IRequestLoader {
|
|
10
|
+
/**
|
|
11
|
+
* Reclaims request to the provider if its processing failed.
|
|
12
|
+
* The request will be returned by some subsequent `fetchNextRequest()` call.
|
|
13
|
+
*/
|
|
14
|
+
reclaimRequest(request: Request, options?: RequestQueueOperationOptions): Promise<RequestQueueOperationInfo | null>;
|
|
15
|
+
addRequest(requestLike: Source, options?: RequestQueueOperationOptions): Promise<RequestQueueOperationInfo>;
|
|
16
|
+
addRequestsBatched(requests: RequestsLike, options?: AddRequestsBatchedOptions): Promise<AddRequestsBatchedResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Remove all requests from the queue but keep the queue itself, resetting it
|
|
19
|
+
* so it can be reused (e.g. across multiple `crawler.run()` calls).
|
|
20
|
+
*
|
|
21
|
+
* Implementations that do not support purging may leave this `undefined`.
|
|
22
|
+
*/
|
|
23
|
+
purge?(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Tells the manager how long a consumer expects to hold a request fetched via `fetchNextRequest()`
|
|
26
|
+
* before marking it handled or reclaiming it (typically the request-handler timeout plus padding).
|
|
27
|
+
*
|
|
28
|
+
* Managers backed by a storage backend that reserves requests via locking use this to avoid handing
|
|
29
|
+
* the same request out again while it is still being processed. Implementations that do not need
|
|
30
|
+
* this hint may leave it `undefined`.
|
|
31
|
+
*/
|
|
32
|
+
setExpectedRequestProcessingTimeSecs?(secs: number): Promise<void>;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|