@crawlee/core 4.0.0-beta.160 → 4.0.0-beta.162
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.
|
@@ -53,7 +53,7 @@ export declare class RequestQueueBackend extends BaseClient implements storage.R
|
|
|
53
53
|
* Computing the flag is expensive: because an in-progress request may sit anywhere in the queue, it
|
|
54
54
|
* forces a scan of every pending entry even when only `limit` items are wanted. Callers that only
|
|
55
55
|
* need the head (e.g. {@link fetchNextRequest}, {@link isEmpty}) leave it off so the scan can stop as
|
|
56
|
-
* soon as the page is filled, keeping those calls O(head) instead of O(
|
|
56
|
+
* soon as the page is filled, keeping those calls O(head) instead of O(pending).
|
|
57
57
|
*/
|
|
58
58
|
private listPendingHead;
|
|
59
59
|
fetchNextRequest(): Promise<storage.UpdateRequestSchema | undefined>;
|
|
@@ -19,11 +19,11 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
19
19
|
pendingRequestCount = 0;
|
|
20
20
|
/**
|
|
21
21
|
* Serializes every operation that reads-then-writes this backend's shared queue state — the
|
|
22
|
-
* `requests` map, the `
|
|
23
|
-
* counts. Those mutations span `await` points, so
|
|
24
|
-
* interleave and corrupt them (e.g. a head scan
|
|
25
|
-
* `addBatchOfRequests` pushes to it). Held by every mutating
|
|
26
|
-
* `isFinished`, whose head scan also prunes `forefrontRequestIds`.
|
|
22
|
+
* `requests` map, the `pendingRequestIds` set, the `forefrontRequestIds` array, the
|
|
23
|
+
* `inProgressRequestIds` set and the request counts. Those mutations span `await` points, so
|
|
24
|
+
* without this mutex a concurrent operation could interleave and corrupt them (e.g. a head scan
|
|
25
|
+
* pruning `forefrontRequestIds` while `addBatchOfRequests` pushes to it). Held by every mutating
|
|
26
|
+
* method as well as by `isEmpty`/`isFinished`, whose head scan also prunes `forefrontRequestIds`.
|
|
27
27
|
*/
|
|
28
28
|
#queueStateMutex = new AsyncQueue();
|
|
29
29
|
#forefrontRequestIds = [];
|
|
@@ -37,6 +37,12 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
37
37
|
*/
|
|
38
38
|
#inProgressRequestIds = new Set();
|
|
39
39
|
#requests = new Map();
|
|
40
|
+
/**
|
|
41
|
+
* IDs of requests that are not yet handled (pending or in progress), in insertion order. Handled
|
|
42
|
+
* requests stay in `requests` for deduplication but are removed from here, so head scans only
|
|
43
|
+
* ever walk the unhandled tail instead of every request the queue has ever seen.
|
|
44
|
+
*/
|
|
45
|
+
#pendingRequestIds = new Set();
|
|
40
46
|
// kept as TS-private: storage-backend tests read this field at runtime
|
|
41
47
|
storageBackend;
|
|
42
48
|
constructor(options) {
|
|
@@ -61,6 +67,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
61
67
|
// leave dangling ids in `forefrontRequestIds`/`inProgressRequestIds`, which a later head
|
|
62
68
|
// scan would resolve to a missing request and dereference.
|
|
63
69
|
this.#requests.clear();
|
|
70
|
+
this.#pendingRequestIds.clear();
|
|
64
71
|
this.#forefrontRequestIds = [];
|
|
65
72
|
this.#inProgressRequestIds.clear();
|
|
66
73
|
}
|
|
@@ -76,6 +83,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
76
83
|
try {
|
|
77
84
|
// Clear all in-memory state
|
|
78
85
|
this.#requests.clear();
|
|
86
|
+
this.#pendingRequestIds.clear();
|
|
79
87
|
this.#forefrontRequestIds = [];
|
|
80
88
|
this.#inProgressRequestIds.clear();
|
|
81
89
|
this.handledRequestCount = 0;
|
|
@@ -90,9 +98,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
90
98
|
for (let i = this.#forefrontRequestIds.length - 1; i >= 0; i--) {
|
|
91
99
|
yield this.#forefrontRequestIds[i];
|
|
92
100
|
}
|
|
93
|
-
|
|
94
|
-
yield key;
|
|
95
|
-
}
|
|
101
|
+
yield* this.#pendingRequestIds;
|
|
96
102
|
}
|
|
97
103
|
/**
|
|
98
104
|
* Scans the queue and returns the pending head — requests that are neither handled nor currently
|
|
@@ -107,7 +113,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
107
113
|
* Computing the flag is expensive: because an in-progress request may sit anywhere in the queue, it
|
|
108
114
|
* forces a scan of every pending entry even when only `limit` items are wanted. Callers that only
|
|
109
115
|
* need the head (e.g. {@link fetchNextRequest}, {@link isEmpty}) leave it off so the scan can stop as
|
|
110
|
-
* soon as the page is filled, keeping those calls O(head) instead of O(
|
|
116
|
+
* soon as the page is filled, keeping those calls O(head) instead of O(pending).
|
|
111
117
|
*/
|
|
112
118
|
async listPendingHead(limit, detectInProgressRequests = false) {
|
|
113
119
|
const items = [];
|
|
@@ -127,11 +133,10 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
127
133
|
}
|
|
128
134
|
seenRequestIds.add(requestId);
|
|
129
135
|
const request = this.#requests.get(requestId);
|
|
130
|
-
//
|
|
136
|
+
// Only `forefrontRequestIds` can still reference a handled request (`orderNo === null`);
|
|
137
|
+
// `pendingRequestIds` drops them on handling. Remember the id so the list gets pruned below.
|
|
131
138
|
if (request.orderNo === null) {
|
|
132
|
-
|
|
133
|
-
handledForefrontIds.add(requestId);
|
|
134
|
-
}
|
|
139
|
+
handledForefrontIds.add(requestId);
|
|
135
140
|
continue;
|
|
136
141
|
}
|
|
137
142
|
// In progress (fetched but not yet handled or reclaimed) — skip it, but remember that the
|
|
@@ -193,6 +198,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
193
198
|
}
|
|
194
199
|
this.#requests.set(requestModel.id, requestModel);
|
|
195
200
|
if (requestModel.orderNo) {
|
|
201
|
+
this.#pendingRequestIds.add(requestModel.id);
|
|
196
202
|
this.pendingRequestCount += 1;
|
|
197
203
|
}
|
|
198
204
|
else {
|
|
@@ -245,6 +251,7 @@ export class RequestQueueBackend extends BaseClient {
|
|
|
245
251
|
const handledAt = request.handledAt ?? new Date().toISOString();
|
|
246
252
|
const requestModel = this.createInternalRequest({ ...request, handledAt }, false);
|
|
247
253
|
this.#requests.set(id, requestModel);
|
|
254
|
+
this.#pendingRequestIds.delete(id);
|
|
248
255
|
// The request is no longer in progress for this client.
|
|
249
256
|
this.#inProgressRequestIds.delete(id);
|
|
250
257
|
if (!wasAlreadyHandled) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/core",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.162",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"@apify/log": "^2.5.18",
|
|
53
53
|
"@apify/timeout": "^0.4.4",
|
|
54
54
|
"@apify/utilities": "^2.15.5",
|
|
55
|
-
"@crawlee/fs-storage": "4.0.0-beta.
|
|
56
|
-
"@crawlee/http-client": "4.0.0-beta.
|
|
57
|
-
"@crawlee/types": "4.0.0-beta.
|
|
58
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
55
|
+
"@crawlee/fs-storage": "4.0.0-beta.162",
|
|
56
|
+
"@crawlee/http-client": "4.0.0-beta.162",
|
|
57
|
+
"@crawlee/types": "4.0.0-beta.162",
|
|
58
|
+
"@crawlee/utils": "4.0.0-beta.162",
|
|
59
59
|
"@sapphire/async-queue": "^1.5.5",
|
|
60
60
|
"@standard-schema/spec": "^1.0.0",
|
|
61
61
|
"@vladfrangu/async_event_emitter": "^2.4.6",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "0896509b1e3df39639d2224b2d565fc592939fd7"
|
|
82
82
|
}
|