@crawlee/core 4.0.0-beta.210 → 4.0.0-beta.212
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/configuration.d.ts +0 -19
- package/configuration.js +8 -8
- package/events/local_event_manager.d.ts +0 -7
- package/events/local_event_manager.js +8 -8
- package/memory-storage/resource-clients/dataset.d.ts +0 -5
- package/memory-storage/resource-clients/dataset.js +15 -16
- package/memory-storage/resource-clients/key-value-store.d.ts +0 -2
- package/memory-storage/resource-clients/key-value-store.js +10 -11
- package/memory-storage/resource-clients/request-queue.d.ts +0 -22
- package/memory-storage/resource-clients/request-queue.js +33 -34
- package/package.json +6 -6
- package/proxy_configuration.d.ts +0 -7
- package/proxy_configuration.js +8 -8
- package/storages/dataset.d.ts +0 -10
- package/storages/dataset.js +13 -13
- package/storages/key_value_store.d.ts +0 -18
- package/storages/key_value_store.js +16 -16
- package/storages/request_dedup_cache.d.ts +0 -2
- package/storages/request_dedup_cache.js +8 -8
- package/storages/request_list.d.ts +0 -57
- package/storages/request_list.js +38 -38
- package/storages/request_manager_tandem.d.ts +0 -12
- package/storages/request_manager_tandem.js +15 -15
- package/storages/request_queue.d.ts +0 -32
- package/storages/request_queue.js +29 -29
- package/storages/storage_instance_manager.js +4 -4
- package/storages/transaction.d.ts +0 -1
- package/storages/transaction.js +2 -2
|
@@ -180,20 +180,20 @@ export class RequestQueue {
|
|
|
180
180
|
parseArgument(requestLike, schemas.anyObject);
|
|
181
181
|
const { forefront } = parseArgument(options, operationOptionsSchema);
|
|
182
182
|
if ('requestsFromUrl' in requestLike) {
|
|
183
|
-
const requests = await this
|
|
184
|
-
const processedRequests = await this
|
|
183
|
+
const requests = await this.#fetchRequestsFromUrl(requestLike);
|
|
184
|
+
const processedRequests = await this.#addFetchedRequests(requestLike, requests, options);
|
|
185
185
|
return { ...processedRequests[0], forefront };
|
|
186
186
|
}
|
|
187
187
|
parseArgument(requestLike, newRequestLikeSchema);
|
|
188
188
|
const request = requestLike instanceof Request ? requestLike : new Request(requestLike);
|
|
189
189
|
if (transaction?.policy.requestQueue === 'deferred') {
|
|
190
|
-
return this
|
|
190
|
+
return this.#addRequestDeferred(transaction, request, forefront);
|
|
191
191
|
}
|
|
192
192
|
const cacheKey = getRequestId(request.uniqueKey);
|
|
193
193
|
const cachedInfo = this.#requestCache.get(cacheKey);
|
|
194
194
|
if (cachedInfo) {
|
|
195
195
|
request.id = cachedInfo.id;
|
|
196
|
-
this
|
|
196
|
+
this.#recordRequestJournalEntry(transaction, [request], forefront, true);
|
|
197
197
|
return {
|
|
198
198
|
wasAlreadyPresent: true,
|
|
199
199
|
// We may assume that if request is in local cache then also the information if the
|
|
@@ -206,13 +206,13 @@ export class RequestQueue {
|
|
|
206
206
|
}
|
|
207
207
|
this.#statsTracker.add('writeCount');
|
|
208
208
|
const { processedRequests } = await this.backend.addBatchOfRequests([request], { forefront });
|
|
209
|
-
this
|
|
209
|
+
this.#recordRequestJournalEntry(transaction, [request], forefront, true);
|
|
210
210
|
const queueOperationInfo = {
|
|
211
211
|
...processedRequests[0],
|
|
212
212
|
uniqueKey: request.uniqueKey,
|
|
213
213
|
forefront,
|
|
214
214
|
};
|
|
215
|
-
this
|
|
215
|
+
this.#cacheRequest(cacheKey, queueOperationInfo);
|
|
216
216
|
this.#requestSeenCache.add(cacheKey, request.id);
|
|
217
217
|
return queueOperationInfo;
|
|
218
218
|
}
|
|
@@ -220,7 +220,7 @@ export class RequestQueue {
|
|
|
220
220
|
* Journals an addition for introspection only; these entries are never replayed. A no-op unless the
|
|
221
221
|
* transaction is open, so detached and outliving writers stay out of the journal.
|
|
222
222
|
*/
|
|
223
|
-
recordRequestJournalEntry(transaction, requests, forefront, writeThrough) {
|
|
223
|
+
#recordRequestJournalEntry(transaction, requests, forefront, writeThrough) {
|
|
224
224
|
if (!transaction?.isActive || requests.length === 0)
|
|
225
225
|
return;
|
|
226
226
|
transaction.recordJournalEntry({
|
|
@@ -239,7 +239,7 @@ export class RequestQueue {
|
|
|
239
239
|
* The requests buffered by the given transaction for this queue, keyed by `uniqueKey` — a dedup
|
|
240
240
|
* index derived from the transaction journal.
|
|
241
241
|
*/
|
|
242
|
-
bufferedRequests(transaction) {
|
|
242
|
+
#bufferedRequests(transaction) {
|
|
243
243
|
const buffered = new Map();
|
|
244
244
|
// Only `deferred` records snapshots, so scanning the journal under `writeThrough` never finds any.
|
|
245
245
|
if (transaction.policy.requestQueue !== 'deferred')
|
|
@@ -259,10 +259,10 @@ export class RequestQueue {
|
|
|
259
259
|
* A new request's `requestId` is the local `uniqueKey` hash and is **provisional** — never write it
|
|
260
260
|
* to `request.id` or the dedup caches. Dedup is cheapest-first: buffer, caches, then a backend probe.
|
|
261
261
|
*/
|
|
262
|
-
async addRequestDeferred(transaction, request, forefront, buffered = this
|
|
262
|
+
async #addRequestDeferred(transaction, request, forefront, buffered = this.#bufferedRequests(transaction)) {
|
|
263
263
|
// This transaction's own buffered adds; the shared caches never see them (provisional ids).
|
|
264
264
|
if (buffered.has(request.uniqueKey)) {
|
|
265
|
-
this
|
|
265
|
+
this.#recordRequestJournalEntry(transaction, [request], forefront, false);
|
|
266
266
|
return {
|
|
267
267
|
wasAlreadyPresent: true,
|
|
268
268
|
wasAlreadyHandled: false,
|
|
@@ -277,7 +277,7 @@ export class RequestQueue {
|
|
|
277
277
|
const cachedInfo = this.#requestCache.get(cacheKey);
|
|
278
278
|
const knownRequestId = cachedInfo?.id ?? this.#requestSeenCache.get(cacheKey);
|
|
279
279
|
if (knownRequestId) {
|
|
280
|
-
this
|
|
280
|
+
this.#recordRequestJournalEntry(transaction, [request], forefront, false);
|
|
281
281
|
return {
|
|
282
282
|
wasAlreadyPresent: true,
|
|
283
283
|
// The dedup cache doesn't track the handled state; only the full record does.
|
|
@@ -290,7 +290,7 @@ export class RequestQueue {
|
|
|
290
290
|
// The caches are bounded, so a miss is not proof of absence - probe for an accurate answer.
|
|
291
291
|
const existing = await this.backend.getRequest(request.uniqueKey);
|
|
292
292
|
if (existing) {
|
|
293
|
-
this
|
|
293
|
+
this.#recordRequestJournalEntry(transaction, [request], forefront, false);
|
|
294
294
|
return {
|
|
295
295
|
wasAlreadyPresent: true,
|
|
296
296
|
wasAlreadyHandled: existing.handledAt != null,
|
|
@@ -348,7 +348,7 @@ export class RequestQueue {
|
|
|
348
348
|
// Only now, with the real backend-assigned ids, may the shared dedup caches be populated.
|
|
349
349
|
for (const processed of processedRequests) {
|
|
350
350
|
const cacheKey = getRequestId(processed.uniqueKey);
|
|
351
|
-
this
|
|
351
|
+
this.#cacheRequest(cacheKey, { ...processed, forefront });
|
|
352
352
|
this.#requestSeenCache.add(cacheKey, processed.requestId);
|
|
353
353
|
}
|
|
354
354
|
if (unprocessedRequests.length > 0) {
|
|
@@ -398,21 +398,21 @@ export class RequestQueue {
|
|
|
398
398
|
requests.push(new Request({ url: requestLike }));
|
|
399
399
|
}
|
|
400
400
|
else if ('requestsFromUrl' in requestLike) {
|
|
401
|
-
const fetchedRequests = await this
|
|
402
|
-
await this
|
|
401
|
+
const fetchedRequests = await this.#fetchRequestsFromUrl(requestLike);
|
|
402
|
+
await this.#addFetchedRequests(requestLike, fetchedRequests, options);
|
|
403
403
|
}
|
|
404
404
|
else {
|
|
405
405
|
requests.push(requestLike instanceof Request ? requestLike : new Request(requestLike));
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
if (transaction?.policy.requestQueue === 'deferred') {
|
|
409
|
-
const buffered = this
|
|
409
|
+
const buffered = this.#bufferedRequests(transaction);
|
|
410
410
|
for (const request of requests) {
|
|
411
|
-
results.processedRequests.push(await this
|
|
411
|
+
results.processedRequests.push(await this.#addRequestDeferred(transaction, request, forefront, buffered));
|
|
412
412
|
}
|
|
413
413
|
return results;
|
|
414
414
|
}
|
|
415
|
-
this
|
|
415
|
+
this.#recordRequestJournalEntry(transaction, requests, forefront, true);
|
|
416
416
|
const requestsToAdd = new Map();
|
|
417
417
|
for (const request of requests) {
|
|
418
418
|
const cacheKey = getCachedRequestId(request.uniqueKey);
|
|
@@ -447,7 +447,7 @@ export class RequestQueue {
|
|
|
447
447
|
results.processedRequests.push(newRequest);
|
|
448
448
|
const cacheKey = getCachedRequestId(newRequest.uniqueKey);
|
|
449
449
|
if (cache) {
|
|
450
|
-
this
|
|
450
|
+
this.#cacheRequest(cacheKey, { ...newRequest, forefront });
|
|
451
451
|
}
|
|
452
452
|
// Unlike `requestCache`, populate this on every batch (including background ones).
|
|
453
453
|
this.#requestSeenCache.add(cacheKey, newRequest.requestId);
|
|
@@ -533,7 +533,7 @@ export class RequestQueue {
|
|
|
533
533
|
const transaction = activeStorageTransaction();
|
|
534
534
|
parseArgument(uniqueKey, uniqueKeySchema);
|
|
535
535
|
// Requests buffered by the active transaction (under the `deferred` write policy) are visible to it.
|
|
536
|
-
const buffered = transaction && this
|
|
536
|
+
const buffered = transaction && this.#bufferedRequests(transaction).get(uniqueKey);
|
|
537
537
|
if (buffered) {
|
|
538
538
|
return Request.fromSchema(buffered);
|
|
539
539
|
}
|
|
@@ -596,7 +596,7 @@ export class RequestQueue {
|
|
|
596
596
|
uniqueKey: request.uniqueKey,
|
|
597
597
|
forefront,
|
|
598
598
|
};
|
|
599
|
-
this
|
|
599
|
+
this.#cacheRequest(getRequestId(request.uniqueKey), queueOperationInfo);
|
|
600
600
|
return queueOperationInfo;
|
|
601
601
|
}
|
|
602
602
|
/**
|
|
@@ -622,7 +622,7 @@ export class RequestQueue {
|
|
|
622
622
|
uniqueKey: request.uniqueKey,
|
|
623
623
|
forefront,
|
|
624
624
|
};
|
|
625
|
-
this
|
|
625
|
+
this.#cacheRequest(getRequestId(request.uniqueKey), queueOperationInfo);
|
|
626
626
|
return queueOperationInfo;
|
|
627
627
|
}
|
|
628
628
|
/**
|
|
@@ -645,7 +645,7 @@ export class RequestQueue {
|
|
|
645
645
|
async checkReadiness() {
|
|
646
646
|
const transaction = activeStorageTransaction();
|
|
647
647
|
// Requests buffered by the active transaction count as pending from its point of view.
|
|
648
|
-
if (transaction && this
|
|
648
|
+
if (transaction && this.#bufferedRequests(transaction).size > 0) {
|
|
649
649
|
return { status: 'ready' };
|
|
650
650
|
}
|
|
651
651
|
// Something fetchable outranks everything below, so this is the only backend call a probe needs.
|
|
@@ -689,7 +689,7 @@ export class RequestQueue {
|
|
|
689
689
|
/**
|
|
690
690
|
* Caches information about request to beware of unneeded addRequest() calls.
|
|
691
691
|
*/
|
|
692
|
-
cacheRequest(cacheKey, queueOperationInfo) {
|
|
692
|
+
#cacheRequest(cacheKey, queueOperationInfo) {
|
|
693
693
|
// Remove the previous entry, as otherwise our cache will never update 👀
|
|
694
694
|
this.#requestCache.remove(cacheKey);
|
|
695
695
|
this.#requestCache.add(cacheKey, {
|
|
@@ -773,7 +773,7 @@ export class RequestQueue {
|
|
|
773
773
|
async getInfo() {
|
|
774
774
|
const transaction = activeStorageTransaction();
|
|
775
775
|
const metadata = await this.backend.getMetadata();
|
|
776
|
-
const bufferedCount = transaction ? this
|
|
776
|
+
const bufferedCount = transaction ? this.#bufferedRequests(transaction).size : 0;
|
|
777
777
|
if (bufferedCount > 0) {
|
|
778
778
|
return {
|
|
779
779
|
...metadata,
|
|
@@ -786,12 +786,12 @@ export class RequestQueue {
|
|
|
786
786
|
/**
|
|
787
787
|
* Fetches URLs from requestsFromUrl and returns them in format of list of requests
|
|
788
788
|
*/
|
|
789
|
-
async fetchRequestsFromUrl(source) {
|
|
789
|
+
async #fetchRequestsFromUrl(source) {
|
|
790
790
|
const { requestsFromUrl, regex, ...sharedOpts } = source;
|
|
791
791
|
// Download remote resource and parse URLs.
|
|
792
792
|
let urlsArr;
|
|
793
793
|
try {
|
|
794
|
-
urlsArr = await this
|
|
794
|
+
urlsArr = await this.#downloadListOfUrls({
|
|
795
795
|
url: requestsFromUrl,
|
|
796
796
|
urlRegExp: regex,
|
|
797
797
|
proxyUrl: (await this.#proxyConfiguration?.newProxyInfo())?.url,
|
|
@@ -810,7 +810,7 @@ export class RequestQueue {
|
|
|
810
810
|
/**
|
|
811
811
|
* Adds all fetched requests from a URL from a remote resource.
|
|
812
812
|
*/
|
|
813
|
-
async addFetchedRequests(source, fetchedRequests, options) {
|
|
813
|
+
async #addFetchedRequests(source, fetchedRequests, options) {
|
|
814
814
|
const { requestsFromUrl, regex } = source;
|
|
815
815
|
const { addedRequests } = await this.addRequestsBatched(fetchedRequests, options);
|
|
816
816
|
this.log.info('Fetched and loaded Requests from a remote resource.', {
|
|
@@ -826,7 +826,7 @@ export class RequestQueue {
|
|
|
826
826
|
/**
|
|
827
827
|
* @internal wraps public utility for mocking purposes
|
|
828
828
|
*/
|
|
829
|
-
async downloadListOfUrls(options) {
|
|
829
|
+
async #downloadListOfUrls(options) {
|
|
830
830
|
return downloadListOfUrls({
|
|
831
831
|
...options,
|
|
832
832
|
httpClient: this.#httpClient,
|
|
@@ -32,7 +32,7 @@ class StorageCache {
|
|
|
32
32
|
return undefined;
|
|
33
33
|
}
|
|
34
34
|
/** Write a single entry into a given tier. */
|
|
35
|
-
setInMap(tier, cls, key, instance, backendCacheKey) {
|
|
35
|
+
#setInMap(tier, cls, key, instance, backendCacheKey) {
|
|
36
36
|
if (!tier.has(cls))
|
|
37
37
|
tier.set(cls, new Map());
|
|
38
38
|
const keyMap = tier.get(cls);
|
|
@@ -45,14 +45,14 @@ class StorageCache {
|
|
|
45
45
|
*/
|
|
46
46
|
set(cls, instance, backendCacheKey, alias) {
|
|
47
47
|
// Always cache by id.
|
|
48
|
-
this
|
|
48
|
+
this.#setInMap(this.byId, cls, instance.id, instance, backendCacheKey);
|
|
49
49
|
// Cache by name — only for named storages.
|
|
50
50
|
if (instance.name) {
|
|
51
|
-
this
|
|
51
|
+
this.#setInMap(this.byName, cls, instance.name, instance, backendCacheKey);
|
|
52
52
|
}
|
|
53
53
|
// Cache by alias — only for unnamed storages opened via alias.
|
|
54
54
|
if (alias !== undefined) {
|
|
55
|
-
this
|
|
55
|
+
this.#setInMap(this.byAlias, cls, alias, instance, backendCacheKey);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
removeFromCache(instance) {
|
|
@@ -189,7 +189,6 @@ export declare class StorageTransaction implements StorageTransactionView {
|
|
|
189
189
|
* partway may have applied some of the writes already.
|
|
190
190
|
*/
|
|
191
191
|
commit(): Promise<void>;
|
|
192
|
-
private flush;
|
|
193
192
|
/**
|
|
194
193
|
* Discards the journaled writes. A no-op unless the transaction is `open` — in particular, calling it
|
|
195
194
|
* after a successful `commit()` (which the crawler's error handling can legitimately do) does nothing
|
package/storages/transaction.js
CHANGED
|
@@ -95,7 +95,7 @@ export class StorageTransaction {
|
|
|
95
95
|
// on every operation - and `@apify/timeout` shares one `AbortController` across nested
|
|
96
96
|
// frames, so a request-handler timeout that already fired would abort the commit of a
|
|
97
97
|
// handler that succeeded. Hence a fresh timeout context, which also provides the time bound.
|
|
98
|
-
await timeoutStorage.exit(async () => addTimeoutToPromise(async () => this
|
|
98
|
+
await timeoutStorage.exit(async () => addTimeoutToPromise(async () => this.#flush(), this.#commitTimeoutMillis, `Committing the storage transaction timed out after ${this.#commitTimeoutMillis / 1000} seconds.`));
|
|
99
99
|
}
|
|
100
100
|
catch (error) {
|
|
101
101
|
this.#state = 'failed';
|
|
@@ -122,7 +122,7 @@ export class StorageTransaction {
|
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
|
-
async flush() {
|
|
125
|
+
async #flush() {
|
|
126
126
|
// Each participating frontend replays all of its buffered entries in one call. Frontends are
|
|
127
127
|
// ordered by storage type: key-value stores and request queues first (idempotent under retry),
|
|
128
128
|
// datasets last (not idempotent), minimizing the blast radius of a partial commit failure.
|