@crawlee/core 4.0.0-beta.15 → 4.0.0-beta.150
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 +14 -14
- package/autoscaling/autoscaled_pool.d.ts +73 -177
- package/autoscaling/autoscaled_pool.js +182 -329
- package/autoscaling/concurrency_system.d.ts +268 -0
- package/autoscaling/concurrency_system.js +364 -0
- package/autoscaling/cpu_load_signal.d.ts +43 -0
- package/autoscaling/cpu_load_signal.js +47 -0
- package/autoscaling/event_loop_load_signal.d.ts +51 -0
- package/autoscaling/event_loop_load_signal.js +60 -0
- package/autoscaling/index.d.ts +6 -1
- package/autoscaling/index.js +6 -1
- package/autoscaling/load_signal.d.ts +98 -0
- package/autoscaling/load_signal.js +103 -0
- package/autoscaling/memory_load_signal.d.ts +47 -0
- package/autoscaling/memory_load_signal.js +106 -0
- package/autoscaling/snapshotter.d.ts +58 -163
- package/autoscaling/snapshotter.js +45 -263
- package/autoscaling/storage_backend_load_signal.d.ts +56 -0
- package/autoscaling/storage_backend_load_signal.js +73 -0
- package/autoscaling/system_status.d.ts +67 -89
- package/autoscaling/system_status.js +92 -122
- package/autoscaling/weighted_avg.d.ts +5 -0
- package/autoscaling/weighted_avg.js +14 -0
- package/byte_utils.d.ts +17 -0
- package/byte_utils.js +42 -0
- package/configuration.d.ts +96 -223
- package/configuration.js +170 -222
- package/cookie_utils.d.ts +3 -2
- package/cookie_utils.js +18 -7
- package/crawlers/context_pipeline.d.ts +10 -1
- package/crawlers/context_pipeline.js +31 -8
- package/crawlers/crawler_commons.d.ts +90 -126
- package/crawlers/crawler_commons.js +1 -108
- package/crawlers/error_snapshotter.d.ts +2 -5
- package/crawlers/error_snapshotter.js +7 -8
- package/crawlers/error_tracker.d.ts +0 -1
- package/crawlers/error_tracker.js +0 -1
- package/crawlers/index.d.ts +1 -3
- package/crawlers/index.js +0 -3
- package/crawlers/internals/types.d.ts +0 -1
- package/crawlers/internals/types.js +0 -1
- package/crawlers/statistics.d.ts +187 -64
- package/crawlers/statistics.js +354 -165
- package/debug.d.ts +36 -0
- package/debug.js +70 -0
- package/enqueue_links/enqueue_links.d.ts +61 -154
- package/enqueue_links/enqueue_links.js +40 -232
- package/enqueue_links/index.d.ts +0 -1
- package/enqueue_links/index.js +0 -1
- package/enqueue_links/shared.d.ts +55 -28
- package/enqueue_links/shared.js +116 -69
- package/errors.d.ts +72 -4
- package/errors.js +89 -5
- package/events/event_manager.d.ts +35 -9
- package/events/event_manager.js +12 -13
- package/events/index.d.ts +0 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -3
- package/events/local_event_manager.js +39 -13
- package/http.d.ts +9 -0
- package/http.js +28 -0
- package/index.d.ts +7 -5
- package/index.js +8 -4
- package/iterables.d.ts +79 -0
- package/iterables.js +134 -0
- package/log.d.ts +77 -1
- package/log.js +104 -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 +44 -0
- package/memory-storage/memory-storage.js +160 -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 +106 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
- package/memory-storage/resource-clients/key-value-store.js +199 -0
- package/memory-storage/resource-clients/request-queue.d.ts +77 -0
- package/memory-storage/resource-clients/request-queue.js +407 -0
- package/memory-storage/utils.d.ts +16 -0
- package/memory-storage/utils.js +41 -0
- package/owned_or_injected.d.ts +58 -0
- package/owned_or_injected.js +98 -0
- package/package.json +13 -12
- package/proxy_configuration.d.ts +22 -128
- package/proxy_configuration.js +32 -144
- package/recoverable_state.d.ts +83 -51
- package/recoverable_state.js +163 -72
- package/request.d.ts +57 -16
- package/request.js +130 -69
- package/router.d.ts +193 -21
- package/router.js +188 -43
- package/serialization.d.ts +0 -1
- package/serialization.js +15 -15
- package/service_locator.d.ts +165 -0
- package/service_locator.js +253 -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 +39 -89
- package/session_pool/session.js +102 -159
- package/session_pool/session_pool.d.ts +67 -91
- package/session_pool/session_pool.js +196 -187
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +109 -56
- package/storages/dataset.js +284 -149
- package/storages/index.d.ts +9 -9
- package/storages/index.js +7 -9
- package/storages/key_value_store.d.ts +183 -48
- package/storages/key_value_store.js +444 -171
- 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 +22 -0
- package/storages/request_dedup_cache.js +48 -0
- package/storages/request_list.d.ts +53 -115
- package/storages/request_list.js +194 -167
- package/storages/request_loader.d.ts +133 -0
- package/storages/request_loader.js +36 -0
- package/storages/request_manager.d.ts +109 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +55 -23
- package/storages/request_manager_tandem.js +139 -57
- package/storages/request_queue.d.ts +286 -48
- package/storages/request_queue.js +757 -218
- package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +43 -91
- package/storages/sitemap_request_loader.js +439 -0
- package/storages/storage_instance_manager.d.ts +87 -0
- package/storages/storage_instance_manager.js +256 -0
- package/storages/storage_stats.d.ts +48 -0
- package/storages/storage_stats.js +29 -0
- package/storages/throttling_request_manager.d.ts +222 -0
- package/storages/throttling_request_manager.js +780 -0
- package/storages/transaction.d.ts +252 -0
- package/storages/transaction.js +251 -0
- package/storages/utils.d.ts +59 -11
- package/storages/utils.js +75 -15
- 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 +0 -6
- package/typedefs.js +0 -1
- package/url.d.ts +9 -0
- package/url.js +11 -0
- package/validators.d.ts +22 -18
- package/validators.js +13 -18
- 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/context_pipeline.d.ts.map +0 -1
- package/crawlers/context_pipeline.js.map +0 -1
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.js.map +0 -1
- package/crawlers/crawler_utils.d.ts +0 -10
- package/crawlers/crawler_utils.d.ts.map +0 -1
- package/crawlers/crawler_utils.js +0 -12
- 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/internals/types.d.ts.map +0 -1
- package/crawlers/internals/types.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 -140
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -40
- 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 -20
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -85
- 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/recoverable_state.d.ts.map +0 -1
- package/recoverable_state.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 +0 -13
- package/storages/access_checking.d.ts.map +0 -1
- package/storages/access_checking.js +0 -14
- 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_list_adapter.d.ts +0 -58
- package/storages/request_list_adapter.d.ts.map +0 -1
- package/storages/request_list_adapter.js +0 -81
- package/storages/request_list_adapter.js.map +0 -1
- package/storages/request_manager_tandem.d.ts.map +0 -1
- package/storages/request_manager_tandem.js.map +0 -1
- package/storages/request_provider.d.ts +0 -371
- package/storages/request_provider.d.ts.map +0 -1
- package/storages/request_provider.js +0 -585
- 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 +0 -430
- 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/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
package/storages/request_list.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { downloadListOfUrls } from '@crawlee/utils';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { log } from '../log.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { EventType } from '../events/event_manager.js';
|
|
5
4
|
import { Request } from '../request.js';
|
|
6
5
|
import { createDeserialize, serializeArray } from '../serialization.js';
|
|
6
|
+
import { serviceLocator } from '../service_locator.js';
|
|
7
|
+
import { parseArgument, schemas, validators } from '../validators.js';
|
|
7
8
|
import { KeyValueStore } from './key_value_store.js';
|
|
8
9
|
import { purgeDefaultStorages } from './utils.js';
|
|
9
10
|
/** @internal */
|
|
@@ -11,6 +12,24 @@ export const STATE_PERSISTENCE_KEY = 'REQUEST_LIST_STATE';
|
|
|
11
12
|
/** @internal */
|
|
12
13
|
export const REQUESTS_PERSISTENCE_KEY = 'REQUEST_LIST_REQUESTS';
|
|
13
14
|
const CONTENT_TYPE_BINARY = 'application/octet-stream';
|
|
15
|
+
const requestListOptionsSchema = z.strictObject({
|
|
16
|
+
sources: schemas.anyArray.optional(), // check only for array and not subtypes to avoid iteration over the whole thing
|
|
17
|
+
sourcesFunction: schemas.anyFunction.optional(),
|
|
18
|
+
persistStateKey: z.string().optional(),
|
|
19
|
+
persistRequestsKey: z.string().optional(),
|
|
20
|
+
state: z
|
|
21
|
+
.strictObject({
|
|
22
|
+
nextIndex: schemas.anyNumber,
|
|
23
|
+
nextUniqueKey: z.string(),
|
|
24
|
+
inProgress: schemas.anyObject, // persisted as an array of unique keys
|
|
25
|
+
})
|
|
26
|
+
.optional(),
|
|
27
|
+
keepDuplicateUrls: z.boolean().default(false),
|
|
28
|
+
proxyConfiguration: validators.proxyConfiguration.optional(),
|
|
29
|
+
httpClient: schemas.httpClient.optional(),
|
|
30
|
+
});
|
|
31
|
+
const listNameSchema = z.string().nullish();
|
|
32
|
+
const openOptionsSchema = z.looseObject({});
|
|
14
33
|
/**
|
|
15
34
|
* Represents a static list of URLs to crawl.
|
|
16
35
|
* The URLs can be provided either in code or parsed from a text file hosted on the web.
|
|
@@ -33,8 +52,8 @@ const CONTENT_TYPE_BINARY = 'application/octet-stream';
|
|
|
33
52
|
* > In practical terms, such a combination can be useful when there is a large number of initial URLs,
|
|
34
53
|
* > but more URLs would be added dynamically by the crawler.
|
|
35
54
|
*
|
|
36
|
-
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
37
|
-
* which are in progress
|
|
55
|
+
* `RequestList` has an internal state where it stores information about which requests were already handled
|
|
56
|
+
* and which are in progress. The state may be automatically persisted to the default
|
|
38
57
|
* {@link KeyValueStore} by setting the `persistStateKey` option so that if the Node.js process is restarted,
|
|
39
58
|
* the crawling can continue where it left off. The automated persisting is launched upon receiving the `persistState`
|
|
40
59
|
* event that is periodically emitted by {@link EventManager}.
|
|
@@ -73,7 +92,7 @@ const CONTENT_TYPE_BINARY = 'application/octet-stream';
|
|
|
73
92
|
* @category Sources
|
|
74
93
|
*/
|
|
75
94
|
export class RequestList {
|
|
76
|
-
log =
|
|
95
|
+
#log = serviceLocator.getLogger().child({ prefix: 'RequestList' });
|
|
77
96
|
/**
|
|
78
97
|
* Array of all requests from all sources, in the order as they appeared in sources.
|
|
79
98
|
* All requests in the array have distinct uniqueKey!
|
|
@@ -81,19 +100,20 @@ export class RequestList {
|
|
|
81
100
|
*/
|
|
82
101
|
requests = [];
|
|
83
102
|
/** Index to the next item in requests array to fetch. All previous requests are either handled or in progress. */
|
|
84
|
-
nextIndex = 0;
|
|
103
|
+
#nextIndex = 0;
|
|
85
104
|
/** Dictionary, key is Request.uniqueKey, value is corresponding index in the requests array. */
|
|
86
|
-
uniqueKeyToIndex = {};
|
|
105
|
+
#uniqueKeyToIndex = {};
|
|
87
106
|
/**
|
|
88
107
|
* Set of `uniqueKey`s of requests that were returned by fetchNextRequest().
|
|
89
108
|
* @internal
|
|
90
109
|
*/
|
|
91
110
|
inProgress = new Set();
|
|
92
111
|
/**
|
|
93
|
-
*
|
|
112
|
+
* `uniqueKey`s of requests that were in progress when the state was last persisted and thus need to be
|
|
113
|
+
* re-crawled after a restart. They are served before advancing through the rest of the sources.
|
|
94
114
|
* @internal
|
|
95
115
|
*/
|
|
96
|
-
|
|
116
|
+
#requestsToRetry = [];
|
|
97
117
|
/**
|
|
98
118
|
* Starts as true because until we handle the first request, the list is effectively persisted by doing nothing.
|
|
99
119
|
* @internal
|
|
@@ -104,77 +124,65 @@ export class RequestList {
|
|
|
104
124
|
* @internal
|
|
105
125
|
*/
|
|
106
126
|
areRequestsPersisted = false;
|
|
107
|
-
isLoading = false;
|
|
108
|
-
isInitialized = false;
|
|
109
|
-
persistStateKey;
|
|
110
|
-
persistRequestsKey;
|
|
111
|
-
initialState;
|
|
112
|
-
store;
|
|
113
|
-
keepDuplicateUrls;
|
|
114
|
-
sources;
|
|
115
|
-
sourcesFunction;
|
|
116
|
-
proxyConfiguration;
|
|
117
|
-
|
|
127
|
+
#isLoading = false;
|
|
128
|
+
#isInitialized = false;
|
|
129
|
+
#persistStateKey;
|
|
130
|
+
#persistRequestsKey;
|
|
131
|
+
#initialState;
|
|
132
|
+
#store;
|
|
133
|
+
#keepDuplicateUrls;
|
|
134
|
+
#sources;
|
|
135
|
+
#sourcesFunction;
|
|
136
|
+
#proxyConfiguration;
|
|
137
|
+
#httpClient;
|
|
118
138
|
/**
|
|
119
139
|
* To create new instance of `RequestList` we need to use `RequestList.open()` factory method.
|
|
120
140
|
* @param options All `RequestList` configuration options
|
|
121
141
|
* @internal
|
|
122
142
|
*/
|
|
123
143
|
constructor(options = {}) {
|
|
124
|
-
const { sources, sourcesFunction, persistStateKey, persistRequestsKey, state, proxyConfiguration, keepDuplicateUrls
|
|
144
|
+
const { sources, sourcesFunction, persistStateKey, persistRequestsKey, state, proxyConfiguration, keepDuplicateUrls, httpClient, } = parseArgument(options, requestListOptionsSchema);
|
|
125
145
|
if (!(sources || sourcesFunction)) {
|
|
126
|
-
throw new
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
persistRequestsKey: ow.optional.string,
|
|
133
|
-
state: ow.optional.object.exactShape({
|
|
134
|
-
nextIndex: ow.number,
|
|
135
|
-
nextUniqueKey: ow.string,
|
|
136
|
-
inProgress: ow.object,
|
|
137
|
-
}),
|
|
138
|
-
keepDuplicateUrls: ow.optional.boolean,
|
|
139
|
-
proxyConfiguration: ow.optional.object,
|
|
140
|
-
}));
|
|
141
|
-
this.persistStateKey = persistStateKey ? `SDK_${persistStateKey}` : persistStateKey;
|
|
142
|
-
this.persistRequestsKey = persistRequestsKey ? `SDK_${persistRequestsKey}` : persistRequestsKey;
|
|
143
|
-
this.initialState = state;
|
|
144
|
-
this.events = config.getEventManager();
|
|
146
|
+
throw new Error('At least one of "sources" or "sourcesFunction" must be provided.');
|
|
147
|
+
}
|
|
148
|
+
this.#persistStateKey = persistStateKey ? `CRAWLEE_${persistStateKey}` : persistStateKey;
|
|
149
|
+
this.#persistRequestsKey = persistRequestsKey ? `CRAWLEE_${persistRequestsKey}` : persistRequestsKey;
|
|
150
|
+
this.#initialState = state;
|
|
151
|
+
this.#httpClient = httpClient;
|
|
145
152
|
// 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
|
-
this
|
|
153
|
+
this.#keepDuplicateUrls = keepDuplicateUrls;
|
|
147
154
|
// Will be empty after initialization to save memory.
|
|
148
|
-
this
|
|
149
|
-
this
|
|
155
|
+
this.#sources = sources ? [...sources] : [];
|
|
156
|
+
this.#sourcesFunction = sourcesFunction;
|
|
150
157
|
// The proxy configuration used for `requestsFromUrl` requests.
|
|
151
|
-
this
|
|
158
|
+
this.#proxyConfiguration = proxyConfiguration;
|
|
159
|
+
this.persistState = this.persistState.bind(this);
|
|
152
160
|
}
|
|
153
161
|
/**
|
|
154
162
|
* Loads all remote sources of URLs and potentially starts periodic state persistence.
|
|
155
163
|
* This function must be called before you can start using the instance in a meaningful way.
|
|
156
164
|
*/
|
|
157
165
|
async initialize() {
|
|
158
|
-
if (this
|
|
166
|
+
if (this.#isLoading) {
|
|
159
167
|
throw new Error('RequestList sources are already loading or were loaded.');
|
|
160
168
|
}
|
|
161
|
-
this
|
|
169
|
+
this.#isLoading = true;
|
|
162
170
|
await purgeDefaultStorages({ onlyPurgeOnce: true });
|
|
163
|
-
const [state, persistedRequests] = await this.
|
|
171
|
+
const [state, persistedRequests] = await this.loadStateAndPersistedRequests();
|
|
164
172
|
// Add persisted requests / new sources in a memory efficient way because with very
|
|
165
173
|
// large lists, we were running out of memory.
|
|
166
174
|
if (persistedRequests) {
|
|
167
|
-
await this.
|
|
175
|
+
await this.addPersistedRequests(persistedRequests);
|
|
168
176
|
}
|
|
169
177
|
else {
|
|
170
|
-
await this.
|
|
178
|
+
await this.addRequestsFromSources();
|
|
171
179
|
}
|
|
172
|
-
this.
|
|
173
|
-
this
|
|
174
|
-
if (this
|
|
175
|
-
await this.
|
|
176
|
-
if (this
|
|
177
|
-
|
|
180
|
+
this.restoreState(state);
|
|
181
|
+
this.#isInitialized = true;
|
|
182
|
+
if (this.#persistRequestsKey && !this.areRequestsPersisted)
|
|
183
|
+
await this.persistRequests();
|
|
184
|
+
if (this.#persistStateKey) {
|
|
185
|
+
serviceLocator.getEventManager().on(EventType.PERSIST_STATE, this.persistState);
|
|
178
186
|
}
|
|
179
187
|
return this;
|
|
180
188
|
}
|
|
@@ -183,17 +191,18 @@ export class RequestList {
|
|
|
183
191
|
* This needs to be done in a memory efficient way. We should update the input
|
|
184
192
|
* to a Stream once apify-client supports streams.
|
|
185
193
|
*/
|
|
186
|
-
async
|
|
194
|
+
async addPersistedRequests(persistedRequests) {
|
|
187
195
|
// We don't need the sources so we purge them to
|
|
188
196
|
// prevent them from hanging in memory.
|
|
189
|
-
for (let i = 0; i < this
|
|
190
|
-
delete
|
|
197
|
+
for (let i = 0; i < this.#sources.length; i++) {
|
|
198
|
+
// oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
|
|
199
|
+
delete this.#sources[i];
|
|
191
200
|
}
|
|
192
|
-
this
|
|
201
|
+
this.#sources = [];
|
|
193
202
|
this.areRequestsPersisted = true;
|
|
194
203
|
const requestStream = createDeserialize(persistedRequests);
|
|
195
204
|
for await (const request of requestStream) {
|
|
196
|
-
this.
|
|
205
|
+
this.addRequest(request);
|
|
197
206
|
}
|
|
198
207
|
}
|
|
199
208
|
/**
|
|
@@ -202,32 +211,36 @@ export class RequestList {
|
|
|
202
211
|
* We need to avoid keeping both sources and requests in memory
|
|
203
212
|
* to reduce memory footprint with very large sources.
|
|
204
213
|
*/
|
|
205
|
-
async
|
|
214
|
+
async addRequestsFromSources() {
|
|
206
215
|
// We'll load all sources in sequence to ensure that they get loaded in the right order.
|
|
207
|
-
const sourcesCount = this
|
|
216
|
+
const sourcesCount = this.#sources.length;
|
|
208
217
|
for (let i = 0; i < sourcesCount; i++) {
|
|
209
|
-
const source = this
|
|
218
|
+
const source = this.#sources[i];
|
|
210
219
|
// Using delete here to drop the original object ASAP to free memory
|
|
211
220
|
// .pop would reverse the array and .shift is SLOW.
|
|
212
|
-
delete
|
|
221
|
+
// oxlint-disable-next-line typescript/no-array-delete
|
|
222
|
+
delete this.#sources[i];
|
|
213
223
|
if (typeof source === 'object' && source.requestsFromUrl) {
|
|
214
|
-
const fetchedRequests = await this.
|
|
215
|
-
await this.
|
|
224
|
+
const fetchedRequests = await this.fetchRequestsFromUrl(source);
|
|
225
|
+
await this.addFetchedRequests(source, fetchedRequests);
|
|
216
226
|
}
|
|
217
227
|
else {
|
|
218
|
-
this.
|
|
228
|
+
this.addRequest(source);
|
|
219
229
|
}
|
|
220
230
|
}
|
|
221
231
|
// Drop the original array full of empty indexes.
|
|
222
|
-
this
|
|
223
|
-
if (this
|
|
232
|
+
this.#sources = [];
|
|
233
|
+
if (this.#sourcesFunction) {
|
|
224
234
|
try {
|
|
225
|
-
const sourcesFromFunction = await this
|
|
235
|
+
const sourcesFromFunction = await this.#sourcesFunction();
|
|
226
236
|
const sourcesFromFunctionCount = sourcesFromFunction.length;
|
|
227
237
|
for (let i = 0; i < sourcesFromFunctionCount; i++) {
|
|
228
|
-
const source = sourcesFromFunction
|
|
229
|
-
|
|
238
|
+
const source = sourcesFromFunction[i];
|
|
239
|
+
// oxlint-disable-next-line typescript/no-array-delete -- intentional, drop the slot so V8 can collect the object
|
|
240
|
+
delete sourcesFromFunction[i];
|
|
241
|
+
this.addRequest(source);
|
|
230
242
|
}
|
|
243
|
+
sourcesFromFunction.length = 0;
|
|
231
244
|
}
|
|
232
245
|
catch (e) {
|
|
233
246
|
const err = e;
|
|
@@ -239,19 +252,30 @@ export class RequestList {
|
|
|
239
252
|
* @inheritDoc
|
|
240
253
|
*/
|
|
241
254
|
async persistState() {
|
|
242
|
-
if (!this
|
|
255
|
+
if (!this.#persistStateKey) {
|
|
243
256
|
throw new Error('Cannot persist state. options.persistStateKey is not set.');
|
|
244
257
|
}
|
|
245
258
|
if (this.isStatePersisted)
|
|
246
259
|
return;
|
|
247
260
|
try {
|
|
248
|
-
this
|
|
249
|
-
await this
|
|
261
|
+
this.#store ??= await KeyValueStore.open();
|
|
262
|
+
await this.#store.setValue(this.#persistStateKey, this.getState());
|
|
250
263
|
this.isStatePersisted = true;
|
|
251
264
|
}
|
|
252
265
|
catch (e) {
|
|
253
266
|
const err = e;
|
|
254
|
-
this
|
|
267
|
+
this.#log.exception(err, 'Attempted to persist state, but failed.');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Removes the `PERSIST_STATE` event listener registered during initialization and persists
|
|
272
|
+
* the current state one last time. Call this when you are done with the `RequestList` to avoid
|
|
273
|
+
* leaking the listener (and the requests it retains) on the shared event manager.
|
|
274
|
+
*/
|
|
275
|
+
async teardown() {
|
|
276
|
+
serviceLocator.getEventManager().off(EventType.PERSIST_STATE, this.persistState);
|
|
277
|
+
if (this.#persistStateKey) {
|
|
278
|
+
await this.persistState();
|
|
255
279
|
}
|
|
256
280
|
}
|
|
257
281
|
/**
|
|
@@ -259,16 +283,16 @@ export class RequestList {
|
|
|
259
283
|
* are automatically persisted at RequestList initialization (if the persistRequestsKey is set),
|
|
260
284
|
* but there's no reason to persist it again afterwards, because RequestList is immutable.
|
|
261
285
|
*/
|
|
262
|
-
async
|
|
286
|
+
async persistRequests() {
|
|
263
287
|
const serializedRequests = await serializeArray(this.requests);
|
|
264
|
-
this
|
|
265
|
-
await this
|
|
288
|
+
this.#store ??= await KeyValueStore.open();
|
|
289
|
+
await this.#store.setValue(this.#persistRequestsKey, serializedRequests, { contentType: CONTENT_TYPE_BINARY });
|
|
266
290
|
this.areRequestsPersisted = true;
|
|
267
291
|
}
|
|
268
292
|
/**
|
|
269
293
|
* Restores RequestList state from a state object.
|
|
270
294
|
*/
|
|
271
|
-
|
|
295
|
+
restoreState(state) {
|
|
272
296
|
// If there's no state it means we've not persisted any (yet).
|
|
273
297
|
if (!state)
|
|
274
298
|
return;
|
|
@@ -285,7 +309,7 @@ export class RequestList {
|
|
|
285
309
|
}
|
|
286
310
|
const deleteFromInProgress = [];
|
|
287
311
|
state.inProgress.forEach((uniqueKey) => {
|
|
288
|
-
const index = this
|
|
312
|
+
const index = this.#uniqueKeyToIndex[uniqueKey];
|
|
289
313
|
if (typeof index !== 'number') {
|
|
290
314
|
throw new Error('The state object is not consistent with RequestList. Unknown uniqueKey is present in the state.');
|
|
291
315
|
}
|
|
@@ -293,7 +317,7 @@ export class RequestList {
|
|
|
293
317
|
deleteFromInProgress.push(uniqueKey);
|
|
294
318
|
}
|
|
295
319
|
});
|
|
296
|
-
this
|
|
320
|
+
this.#nextIndex = state.nextIndex;
|
|
297
321
|
this.inProgress = new Set(state.inProgress);
|
|
298
322
|
// WORKAROUND:
|
|
299
323
|
// It happened to some users that state object contained something like:
|
|
@@ -309,36 +333,36 @@ export class RequestList {
|
|
|
309
333
|
// As a workaround, we just remove all inProgress requests whose index >= nextIndex,
|
|
310
334
|
// since they will be crawled again.
|
|
311
335
|
if (deleteFromInProgress.length) {
|
|
312
|
-
this
|
|
336
|
+
this.#log.warning("RequestList's in-progress field is not consistent, skipping invalid in-progress entries", {
|
|
313
337
|
deleteFromInProgress,
|
|
314
338
|
});
|
|
315
339
|
for (const uniqueKey of deleteFromInProgress) {
|
|
316
340
|
this.inProgress.delete(uniqueKey);
|
|
317
341
|
}
|
|
318
342
|
}
|
|
319
|
-
// All in-progress requests need to be re-crawled
|
|
320
|
-
this
|
|
343
|
+
// All in-progress requests were interrupted and need to be re-crawled.
|
|
344
|
+
this.#requestsToRetry = [...this.inProgress];
|
|
321
345
|
}
|
|
322
346
|
/**
|
|
323
347
|
* Attempts to load state and requests using the `RequestList` configuration
|
|
324
348
|
* and returns a tuple of [state, requests] where each may be null if not loaded.
|
|
325
349
|
*/
|
|
326
|
-
async
|
|
350
|
+
async loadStateAndPersistedRequests() {
|
|
327
351
|
let state;
|
|
328
352
|
let persistedRequests;
|
|
329
|
-
if (this
|
|
330
|
-
state = this
|
|
331
|
-
this
|
|
353
|
+
if (this.#initialState) {
|
|
354
|
+
state = this.#initialState;
|
|
355
|
+
this.#log.debug('Loaded state from options.state argument.');
|
|
332
356
|
}
|
|
333
|
-
else if (this
|
|
334
|
-
state = await this.
|
|
357
|
+
else if (this.#persistStateKey) {
|
|
358
|
+
state = await this.getPersistedState(this.#persistStateKey);
|
|
335
359
|
if (state)
|
|
336
|
-
this
|
|
360
|
+
this.#log.debug('Loaded state from key value store using the persistStateKey.');
|
|
337
361
|
}
|
|
338
|
-
if (this
|
|
339
|
-
persistedRequests = await this.
|
|
362
|
+
if (this.#persistRequestsKey) {
|
|
363
|
+
persistedRequests = await this.getPersistedState(this.#persistRequestsKey);
|
|
340
364
|
if (persistedRequests)
|
|
341
|
-
this
|
|
365
|
+
this.#log.debug('Loaded requests from key value store using the persistRequestsKey.');
|
|
342
366
|
}
|
|
343
367
|
return [state, persistedRequests];
|
|
344
368
|
}
|
|
@@ -347,45 +371,41 @@ export class RequestList {
|
|
|
347
371
|
* Note that the object's fields can change in future releases.
|
|
348
372
|
*/
|
|
349
373
|
getState() {
|
|
350
|
-
this.
|
|
374
|
+
this.ensureIsInitialized();
|
|
351
375
|
return {
|
|
352
|
-
nextIndex: this
|
|
353
|
-
nextUniqueKey: this
|
|
376
|
+
nextIndex: this.#nextIndex,
|
|
377
|
+
nextUniqueKey: this.#nextIndex < this.requests.length ? this.requests[this.#nextIndex].uniqueKey : null,
|
|
354
378
|
inProgress: [...this.inProgress],
|
|
355
379
|
};
|
|
356
380
|
}
|
|
357
381
|
/**
|
|
358
382
|
* @inheritDoc
|
|
359
383
|
*/
|
|
360
|
-
async
|
|
361
|
-
this.
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
async isFinished() {
|
|
368
|
-
this._ensureIsInitialized();
|
|
369
|
-
return this.inProgress.size === 0 && this.nextIndex >= this.requests.length;
|
|
384
|
+
async checkReadiness() {
|
|
385
|
+
this.ensureIsInitialized();
|
|
386
|
+
if (this.#requestsToRetry.length > 0 || this.#nextIndex < this.requests.length) {
|
|
387
|
+
return { status: 'ready' };
|
|
388
|
+
}
|
|
389
|
+
// `#requestsToRetry` is a subset of `inProgress`, so nothing in progress means nothing left to re-serve.
|
|
390
|
+
return this.inProgress.size === 0 ? { status: 'finished' } : { status: 'waiting' };
|
|
370
391
|
}
|
|
371
392
|
/**
|
|
372
393
|
* @inheritDoc
|
|
373
394
|
*/
|
|
374
395
|
async fetchNextRequest() {
|
|
375
|
-
this.
|
|
376
|
-
// First
|
|
377
|
-
const uniqueKey = this.
|
|
396
|
+
this.ensureIsInitialized();
|
|
397
|
+
// First re-serve any requests that were interrupted before the last state persist.
|
|
398
|
+
const uniqueKey = this.#requestsToRetry.shift();
|
|
378
399
|
if (uniqueKey) {
|
|
379
|
-
this
|
|
380
|
-
const index = this.uniqueKeyToIndex[uniqueKey];
|
|
400
|
+
const index = this.#uniqueKeyToIndex[uniqueKey];
|
|
381
401
|
return this.ensureRequest(this.requests[index], index);
|
|
382
402
|
}
|
|
383
403
|
// Otherwise return next request.
|
|
384
|
-
if (this
|
|
385
|
-
const index = this
|
|
404
|
+
if (this.#nextIndex < this.requests.length) {
|
|
405
|
+
const index = this.#nextIndex;
|
|
386
406
|
const request = this.requests[index];
|
|
387
407
|
this.inProgress.add(request.uniqueKey);
|
|
388
|
-
this
|
|
408
|
+
this.#nextIndex++;
|
|
389
409
|
this.isStatePersisted = false;
|
|
390
410
|
return this.ensureRequest(request, index);
|
|
391
411
|
}
|
|
@@ -412,34 +432,24 @@ export class RequestList {
|
|
|
412
432
|
/**
|
|
413
433
|
* @inheritDoc
|
|
414
434
|
*/
|
|
415
|
-
async
|
|
435
|
+
async markRequestAsHandled(request) {
|
|
416
436
|
const { uniqueKey } = request;
|
|
417
|
-
this.
|
|
418
|
-
this.
|
|
419
|
-
this.
|
|
437
|
+
this.ensureUniqueKeyValid(uniqueKey);
|
|
438
|
+
this.ensureInProgress(uniqueKey);
|
|
439
|
+
this.ensureIsInitialized();
|
|
420
440
|
this.inProgress.delete(uniqueKey);
|
|
421
441
|
this.isStatePersisted = false;
|
|
422
442
|
}
|
|
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
443
|
/**
|
|
434
444
|
* Adds all fetched requests from a URL from a remote resource.
|
|
435
445
|
*/
|
|
436
|
-
async
|
|
446
|
+
async addFetchedRequests(source, fetchedRequests) {
|
|
437
447
|
const { requestsFromUrl, regex } = source;
|
|
438
448
|
const originalLength = this.requests.length;
|
|
439
|
-
fetchedRequests.forEach((request) => this.
|
|
449
|
+
fetchedRequests.forEach((request) => this.addRequest(request));
|
|
440
450
|
const fetchedCount = fetchedRequests.length;
|
|
441
451
|
const importedCount = this.requests.length - originalLength;
|
|
442
|
-
this
|
|
452
|
+
this.#log.info('Fetched and loaded Requests from a remote resource.', {
|
|
443
453
|
requestsFromUrl,
|
|
444
454
|
regex,
|
|
445
455
|
fetchedCount,
|
|
@@ -448,23 +458,23 @@ export class RequestList {
|
|
|
448
458
|
sample: JSON.stringify(fetchedRequests.slice(0, 5)),
|
|
449
459
|
});
|
|
450
460
|
}
|
|
451
|
-
async
|
|
452
|
-
this
|
|
453
|
-
const state = await this
|
|
461
|
+
async getPersistedState(key) {
|
|
462
|
+
this.#store ??= await KeyValueStore.open();
|
|
463
|
+
const state = await this.#store.getValue(key);
|
|
454
464
|
return state;
|
|
455
465
|
}
|
|
456
466
|
/**
|
|
457
467
|
* Fetches URLs from requestsFromUrl and returns them in format of list of requests
|
|
458
468
|
*/
|
|
459
|
-
async
|
|
469
|
+
async fetchRequestsFromUrl(source) {
|
|
460
470
|
const { requestsFromUrl, regex, ...sharedOpts } = source;
|
|
461
471
|
// Download remote resource and parse URLs.
|
|
462
472
|
let urlsArr;
|
|
463
473
|
try {
|
|
464
|
-
urlsArr = await this.
|
|
474
|
+
urlsArr = await this.downloadListOfUrls({
|
|
465
475
|
url: requestsFromUrl,
|
|
466
476
|
urlRegExp: regex,
|
|
467
|
-
proxyUrl: await this
|
|
477
|
+
proxyUrl: (await this.#proxyConfiguration?.newProxyInfo())?.url,
|
|
468
478
|
});
|
|
469
479
|
}
|
|
470
480
|
catch (err) {
|
|
@@ -472,7 +482,7 @@ export class RequestList {
|
|
|
472
482
|
}
|
|
473
483
|
// Skip if resource contained no URLs.
|
|
474
484
|
if (!urlsArr.length) {
|
|
475
|
-
this
|
|
485
|
+
this.#log.warning('The fetched list contains no valid URLs.', { requestsFromUrl, regex });
|
|
476
486
|
return [];
|
|
477
487
|
}
|
|
478
488
|
return urlsArr.map((url) => ({ url, ...sharedOpts }));
|
|
@@ -482,7 +492,7 @@ export class RequestList {
|
|
|
482
492
|
* If the `source` parameter is a string or plain object and not an instance
|
|
483
493
|
* of a `Request`, then the function creates a `Request` instance.
|
|
484
494
|
*/
|
|
485
|
-
|
|
495
|
+
addRequest(source) {
|
|
486
496
|
let request;
|
|
487
497
|
const type = typeof source;
|
|
488
498
|
if (type === 'string') {
|
|
@@ -500,61 +510,76 @@ export class RequestList {
|
|
|
500
510
|
const hasUniqueKey = Reflect.has(Object(source), 'uniqueKey');
|
|
501
511
|
request.uniqueKey ??= Request.computeUniqueKey(request);
|
|
502
512
|
// Add index to uniqueKey if duplicates are to be kept
|
|
503
|
-
if (this
|
|
513
|
+
if (this.#keepDuplicateUrls && !hasUniqueKey) {
|
|
504
514
|
request.uniqueKey += `-${this.requests.length}`;
|
|
505
515
|
}
|
|
506
516
|
const { uniqueKey } = request;
|
|
507
|
-
this.
|
|
517
|
+
this.ensureUniqueKeyValid(uniqueKey);
|
|
508
518
|
// Skip requests with duplicate uniqueKey
|
|
509
|
-
if (!Object.hasOwn(this
|
|
510
|
-
this
|
|
519
|
+
if (!Object.hasOwn(this.#uniqueKeyToIndex, uniqueKey)) {
|
|
520
|
+
this.#uniqueKeyToIndex[uniqueKey] = this.requests.length;
|
|
511
521
|
this.requests.push(request);
|
|
512
522
|
}
|
|
513
|
-
else if (this
|
|
514
|
-
this
|
|
523
|
+
else if (this.#keepDuplicateUrls) {
|
|
524
|
+
this.#log.warning(`Duplicate uniqueKey: ${uniqueKey} found while the keepDuplicateUrls option was set. Check your sources' unique keys.`);
|
|
515
525
|
}
|
|
516
526
|
}
|
|
517
527
|
/**
|
|
518
528
|
* Helper function that validates unique key.
|
|
519
529
|
* Throws an error if uniqueKey is not a non-empty string.
|
|
520
530
|
*/
|
|
521
|
-
|
|
531
|
+
ensureUniqueKeyValid(uniqueKey) {
|
|
522
532
|
if (typeof uniqueKey !== 'string' || !uniqueKey) {
|
|
523
533
|
throw new Error("Request object's uniqueKey must be a non-empty string");
|
|
524
534
|
}
|
|
525
535
|
}
|
|
526
536
|
/**
|
|
527
|
-
* Checks that request is
|
|
537
|
+
* Checks that a request is currently being processed and throws an error if not.
|
|
528
538
|
*/
|
|
529
|
-
|
|
539
|
+
ensureInProgress(uniqueKey) {
|
|
530
540
|
if (!this.inProgress.has(uniqueKey)) {
|
|
531
541
|
throw new Error(`The request is not being processed (uniqueKey: ${uniqueKey})`);
|
|
532
542
|
}
|
|
533
|
-
if (this.reclaimed.has(uniqueKey)) {
|
|
534
|
-
throw new Error(`The request was already reclaimed (uniqueKey: ${uniqueKey})`);
|
|
535
|
-
}
|
|
536
543
|
}
|
|
537
544
|
/**
|
|
538
545
|
* Throws an error if request list wasn't initialized.
|
|
539
546
|
*/
|
|
540
|
-
|
|
541
|
-
if (!this
|
|
547
|
+
ensureIsInitialized() {
|
|
548
|
+
if (!this.#isInitialized) {
|
|
542
549
|
throw new Error('RequestList is not initialized; you must call "await requestList.initialize()" before using it!');
|
|
543
550
|
}
|
|
544
551
|
}
|
|
545
552
|
/**
|
|
546
553
|
* Returns the total number of unique requests present in the `RequestList`.
|
|
547
554
|
*/
|
|
548
|
-
|
|
549
|
-
this.
|
|
555
|
+
async getTotalCount() {
|
|
556
|
+
this.ensureIsInitialized();
|
|
550
557
|
return this.requests.length;
|
|
551
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Returns the number of pending requests in the `RequestList`.
|
|
561
|
+
*/
|
|
562
|
+
async getPendingCount() {
|
|
563
|
+
this.ensureIsInitialized();
|
|
564
|
+
return this.requests.length - (this.#nextIndex - this.inProgress.size);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Combines this list with a request manager (a {@link RequestQueue} by default) into a
|
|
568
|
+
* {@link RequestManagerTandem}, allowing requests to be added and reclaimed while still
|
|
569
|
+
* being read from this list first.
|
|
570
|
+
*/
|
|
571
|
+
async toTandem(requestManager) {
|
|
572
|
+
// Import here to avoid circular imports.
|
|
573
|
+
const { RequestManagerTandem } = await import('./request_manager_tandem.js');
|
|
574
|
+
const { RequestQueue } = await import('./request_queue.js');
|
|
575
|
+
return new RequestManagerTandem(this, requestManager ?? (await RequestQueue.open()));
|
|
576
|
+
}
|
|
552
577
|
/**
|
|
553
578
|
* @inheritDoc
|
|
554
579
|
*/
|
|
555
|
-
|
|
556
|
-
this.
|
|
557
|
-
return this
|
|
580
|
+
async getHandledCount() {
|
|
581
|
+
this.ensureIsInitialized();
|
|
582
|
+
return this.#nextIndex - this.inProgress.size;
|
|
558
583
|
}
|
|
559
584
|
/**
|
|
560
585
|
* Opens a request list and returns a promise resolving to an instance
|
|
@@ -617,9 +642,9 @@ export class RequestList {
|
|
|
617
642
|
return rl;
|
|
618
643
|
}
|
|
619
644
|
const listName = listNameOrOptions;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
645
|
+
parseArgument(listName, listNameSchema);
|
|
646
|
+
parseArgument(sources, schemas.anyArray);
|
|
647
|
+
parseArgument(options, openOptionsSchema);
|
|
623
648
|
const rl = new RequestList({
|
|
624
649
|
...options,
|
|
625
650
|
persistStateKey: listName ? `${listName}-${STATE_PERSISTENCE_KEY}` : options.persistStateKey,
|
|
@@ -632,8 +657,10 @@ export class RequestList {
|
|
|
632
657
|
/**
|
|
633
658
|
* @internal wraps public utility for mocking purposes
|
|
634
659
|
*/
|
|
635
|
-
async
|
|
636
|
-
return downloadListOfUrls(
|
|
660
|
+
async downloadListOfUrls(options) {
|
|
661
|
+
return downloadListOfUrls({
|
|
662
|
+
...options,
|
|
663
|
+
httpClient: this.#httpClient,
|
|
664
|
+
});
|
|
637
665
|
}
|
|
638
666
|
}
|
|
639
|
-
//# sourceMappingURL=request_list.js.map
|