@crawlee/core 4.0.0-beta.99 → 4.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/configuration.d.ts +16 -47
- package/configuration.js +13 -25
- package/debug.js +4 -4
- package/errors.d.ts +28 -38
- package/errors.js +33 -47
- package/events/event_manager.d.ts +2 -2
- package/events/event_manager.js +7 -6
- package/events/index.d.ts +1 -0
- package/events/local_event_manager.d.ts +1 -8
- package/events/local_event_manager.js +13 -13
- package/events/system_info.d.ts +38 -0
- package/index.d.ts +2 -8
- package/index.js +4 -8
- package/internal.d.ts +8 -0
- package/internal.js +9 -0
- package/log.d.ts +10 -11
- package/log.js +52 -20
- package/memory-storage/memory-storage.d.ts +15 -18
- package/memory-storage/memory-storage.js +80 -58
- package/memory-storage/resource-clients/dataset.d.ts +1 -6
- package/memory-storage/resource-clients/dataset.js +23 -31
- package/memory-storage/resource-clients/key-value-store.d.ts +1 -10
- package/memory-storage/resource-clients/key-value-store.js +43 -67
- package/memory-storage/resource-clients/request-queue.d.ts +1 -42
- package/memory-storage/resource-clients/request-queue.js +109 -117
- package/owned_or_injected.d.ts +1 -3
- package/owned_or_injected.js +17 -17
- package/package.json +17 -20
- package/proxy_configuration.d.ts +21 -26
- package/proxy_configuration.js +35 -25
- package/recoverable_state.d.ts +104 -47
- package/recoverable_state.js +199 -74
- package/request.d.ts +20 -107
- package/request.js +78 -244
- package/serialization.js +17 -16
- package/service_locator.d.ts +22 -10
- package/service_locator.js +59 -48
- package/storages/batched_adds.d.ts +37 -0
- package/storages/batched_adds.js +73 -0
- package/storages/dataset.d.ts +13 -8
- package/storages/dataset.js +149 -40
- package/storages/index.d.ts +4 -4
- package/storages/index.js +2 -4
- package/storages/key_value_store.d.ts +16 -35
- package/storages/key_value_store.js +223 -110
- package/storages/key_value_store_codec.js +6 -11
- package/storages/request_dedup_cache.d.ts +1 -4
- package/storages/request_dedup_cache.js +15 -15
- package/storages/request_list.d.ts +9 -104
- package/storages/request_list.js +236 -233
- package/storages/request_loader.d.ts +49 -18
- package/storages/request_loader.js +36 -1
- package/storages/request_manager.d.ts +86 -0
- package/storages/request_manager_tandem.d.ts +14 -38
- package/storages/request_manager_tandem.js +67 -64
- package/storages/request_queue.d.ts +23 -50
- package/storages/request_queue.js +371 -226
- package/storages/storage_instance_manager.d.ts +2 -4
- package/storages/storage_instance_manager.js +21 -21
- package/storages/storage_stats.d.ts +1 -1
- package/storages/storage_stats.js +4 -4
- package/storages/transaction.d.ts +270 -0
- package/storages/transaction.js +296 -0
- package/storages/utils.d.ts +6 -3
- package/storages/utils.js +11 -2
- package/system-info/runtime.js +7 -7
- package/url.d.ts +9 -0
- package/url.js +11 -0
- package/validators.d.ts +23 -25
- package/validators.js +14 -25
- package/autoscaling/autoscaled_pool.d.ts +0 -213
- package/autoscaling/autoscaled_pool.js +0 -378
- package/autoscaling/client_load_signal.d.ts +0 -59
- package/autoscaling/client_load_signal.js +0 -73
- package/autoscaling/concurrency_system.d.ts +0 -283
- package/autoscaling/concurrency_system.js +0 -350
- package/autoscaling/cpu_load_signal.d.ts +0 -44
- package/autoscaling/cpu_load_signal.js +0 -46
- package/autoscaling/event_loop_load_signal.d.ts +0 -54
- package/autoscaling/event_loop_load_signal.js +0 -60
- package/autoscaling/index.d.ts +0 -9
- package/autoscaling/index.js +0 -9
- package/autoscaling/load_signal.d.ts +0 -99
- package/autoscaling/load_signal.js +0 -103
- package/autoscaling/memory_load_signal.d.ts +0 -56
- package/autoscaling/memory_load_signal.js +0 -106
- package/autoscaling/snapshotter.d.ts +0 -87
- package/autoscaling/snapshotter.js +0 -67
- package/autoscaling/system_status.d.ts +0 -161
- package/autoscaling/system_status.js +0 -139
- package/autoscaling/weighted_avg.d.ts +0 -5
- package/autoscaling/weighted_avg.js +0 -14
- package/cookie_utils.d.ts +0 -44
- package/cookie_utils.js +0 -122
- package/crawlers/context_pipeline.d.ts +0 -70
- package/crawlers/context_pipeline.js +0 -122
- package/crawlers/crawler_commons.d.ts +0 -257
- package/crawlers/crawler_commons.js +0 -107
- package/crawlers/error_snapshotter.d.ts +0 -59
- package/crawlers/error_snapshotter.js +0 -117
- package/crawlers/error_tracker.d.ts +0 -54
- package/crawlers/error_tracker.js +0 -308
- package/crawlers/index.d.ts +0 -5
- package/crawlers/index.js +0 -5
- package/crawlers/internals/types.d.ts +0 -7
- package/crawlers/statistics.d.ts +0 -209
- package/crawlers/statistics.js +0 -350
- package/enqueue_links/enqueue_links.d.ts +0 -264
- package/enqueue_links/enqueue_links.js +0 -271
- package/enqueue_links/index.d.ts +0 -2
- package/enqueue_links/index.js +0 -2
- package/enqueue_links/shared.d.ts +0 -83
- package/enqueue_links/shared.js +0 -221
- package/router.d.ts +0 -309
- package/router.js +0 -309
- package/session_pool/consts.d.ts +0 -3
- package/session_pool/consts.js +0 -3
- package/session_pool/errors.d.ts +0 -7
- package/session_pool/errors.js +0 -11
- package/session_pool/fingerprint.d.ts +0 -9
- package/session_pool/fingerprint.js +0 -30
- package/session_pool/index.d.ts +0 -4
- package/session_pool/index.js +0 -4
- package/session_pool/session.d.ts +0 -161
- package/session_pool/session.js +0 -218
- package/session_pool/session_pool.d.ts +0 -246
- package/session_pool/session_pool.js +0 -386
- package/storages/access_checking.d.ts +0 -12
- package/storages/access_checking.js +0 -17
- package/storages/sitemap_request_loader.d.ts +0 -249
- package/storages/sitemap_request_loader.js +0 -432
- /package/{crawlers/internals/types.js → events/system_info.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { parseArgument, schemas } from '@crawlee/utils/internal';
|
|
3
3
|
import { BaseClient } from './common/base-client.js';
|
|
4
4
|
/**
|
|
5
5
|
* This is what API returns in the x-apify-pagination-limit
|
|
@@ -22,54 +22,46 @@ export class DatasetBackend extends BaseClient {
|
|
|
22
22
|
accessedAt = new Date();
|
|
23
23
|
modifiedAt = new Date();
|
|
24
24
|
itemCount = 0;
|
|
25
|
-
datasetEntries = new Map();
|
|
26
|
-
storageBackend;
|
|
25
|
+
#datasetEntries = new Map();
|
|
26
|
+
#storageBackend;
|
|
27
27
|
constructor(options) {
|
|
28
28
|
super(options.id ?? randomUUID());
|
|
29
29
|
this.name = options.name;
|
|
30
30
|
this.cacheKey = options.cacheKey ?? this.name ?? this.id;
|
|
31
|
-
this
|
|
31
|
+
this.#storageBackend = options.storageBackend;
|
|
32
32
|
}
|
|
33
33
|
async getMetadata() {
|
|
34
|
-
this
|
|
34
|
+
this.#updateTimestamps(false);
|
|
35
35
|
return this.toDatasetInfo();
|
|
36
36
|
}
|
|
37
37
|
async drop() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
oldBackend.itemCount = 0;
|
|
42
|
-
oldBackend.datasetEntries.clear();
|
|
38
|
+
if (this.#storageBackend.evictBackend('Dataset', this.id)) {
|
|
39
|
+
this.itemCount = 0;
|
|
40
|
+
this.#datasetEntries.clear();
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
async purge() {
|
|
46
44
|
this.itemCount = 0;
|
|
47
|
-
this
|
|
48
|
-
this
|
|
45
|
+
this.#datasetEntries.clear();
|
|
46
|
+
this.#updateTimestamps(true);
|
|
49
47
|
}
|
|
50
48
|
getData(options = {}) {
|
|
51
|
-
const { desc, limit, offset } =
|
|
52
|
-
|
|
53
|
-
desc: s.boolean().optional(),
|
|
54
|
-
limit: s.number().int().optional(),
|
|
55
|
-
offset: s.number().int().optional(),
|
|
56
|
-
})
|
|
57
|
-
.parse(options);
|
|
58
|
-
return this.getDataPage({
|
|
49
|
+
const { desc, limit, offset } = parseArgument(options, schemas.datasetListItemsOptions);
|
|
50
|
+
return this.#getDataPage({
|
|
59
51
|
desc,
|
|
60
52
|
offset: offset ?? 0,
|
|
61
53
|
limit: Math.min(limit ?? LIST_ITEMS_LIMIT, LIST_ITEMS_LIMIT),
|
|
62
54
|
});
|
|
63
55
|
}
|
|
64
|
-
async getDataPage(options = {}) {
|
|
56
|
+
async #getDataPage(options = {}) {
|
|
65
57
|
const { limit = LIST_ITEMS_LIMIT, offset = 0, desc } = options;
|
|
66
|
-
const [start, end] = this
|
|
58
|
+
const [start, end] = this.#getStartAndEndIndexes(desc ? Math.max(this.itemCount - offset - limit, 0) : offset, limit);
|
|
67
59
|
const items = [];
|
|
68
60
|
for (let idx = start; idx < end; idx++) {
|
|
69
|
-
const entryNumber = this
|
|
70
|
-
items.push(this
|
|
61
|
+
const entryNumber = this.#generateLocalEntryName(idx);
|
|
62
|
+
items.push(this.#datasetEntries.get(entryNumber));
|
|
71
63
|
}
|
|
72
|
-
this
|
|
64
|
+
this.#updateTimestamps(false);
|
|
73
65
|
return {
|
|
74
66
|
count: items.length,
|
|
75
67
|
desc: desc ?? false,
|
|
@@ -81,10 +73,10 @@ export class DatasetBackend extends BaseClient {
|
|
|
81
73
|
}
|
|
82
74
|
async pushData(items) {
|
|
83
75
|
for (const entry of items) {
|
|
84
|
-
const idx = this
|
|
85
|
-
this
|
|
76
|
+
const idx = this.#generateLocalEntryName(++this.itemCount);
|
|
77
|
+
this.#datasetEntries.set(idx, JSON.parse(JSON.stringify(entry)));
|
|
86
78
|
}
|
|
87
|
-
this
|
|
79
|
+
this.#updateTimestamps(true);
|
|
88
80
|
}
|
|
89
81
|
toDatasetInfo() {
|
|
90
82
|
return {
|
|
@@ -96,15 +88,15 @@ export class DatasetBackend extends BaseClient {
|
|
|
96
88
|
name: this.name,
|
|
97
89
|
};
|
|
98
90
|
}
|
|
99
|
-
generateLocalEntryName(idx) {
|
|
91
|
+
#generateLocalEntryName(idx) {
|
|
100
92
|
return idx.toString().padStart(LOCAL_ENTRY_NAME_DIGITS, '0');
|
|
101
93
|
}
|
|
102
|
-
getStartAndEndIndexes(offset, limit = this.itemCount) {
|
|
94
|
+
#getStartAndEndIndexes(offset, limit = this.itemCount) {
|
|
103
95
|
const start = offset + 1;
|
|
104
96
|
const end = Math.min(offset + limit, this.itemCount) + 1;
|
|
105
97
|
return [start, end];
|
|
106
98
|
}
|
|
107
|
-
updateTimestamps(hasBeenModified) {
|
|
99
|
+
#updateTimestamps(hasBeenModified) {
|
|
108
100
|
this.accessedAt = new Date();
|
|
109
101
|
if (hasBeenModified) {
|
|
110
102
|
this.modifiedAt = new Date();
|
|
@@ -19,6 +19,7 @@ export interface InternalKeyRecord {
|
|
|
19
19
|
extension: string;
|
|
20
20
|
}
|
|
21
21
|
export declare class KeyValueStoreBackend extends BaseClient implements storage.KeyValueStoreBackend {
|
|
22
|
+
#private;
|
|
22
23
|
name?: string;
|
|
23
24
|
/**
|
|
24
25
|
* The key used for cache lookup. For named storages, this equals the name. For alias (unnamed)
|
|
@@ -28,19 +29,10 @@ export declare class KeyValueStoreBackend extends BaseClient implements storage.
|
|
|
28
29
|
createdAt: Date;
|
|
29
30
|
accessedAt: Date;
|
|
30
31
|
modifiedAt: Date;
|
|
31
|
-
private readonly keyValueEntries;
|
|
32
|
-
private readonly storageBackend;
|
|
33
32
|
constructor(options: KeyValueStoreBackendOptions);
|
|
34
33
|
getMetadata(): Promise<storage.KeyValueStoreInfo>;
|
|
35
34
|
drop(): Promise<void>;
|
|
36
35
|
purge(): Promise<void>;
|
|
37
|
-
/**
|
|
38
|
-
* Purges every record except the run's input. Used by {@link MemoryStorageBackend.purge} for the
|
|
39
|
-
* default key-value store, mirroring `FileSystemStorageBackend`, which preserves `INPUT` (and its
|
|
40
|
-
* extension variants) when purging the default store. The in-memory key has no extension, so we
|
|
41
|
-
* preserve the bare `INPUT` key only.
|
|
42
|
-
*/
|
|
43
|
-
purgeExceptInput(): Promise<void>;
|
|
44
36
|
listKeys(options?: storage.KeyValueStoreListKeysOptions): Promise<storage.KeyValueStoreListKeysResult>;
|
|
45
37
|
/**
|
|
46
38
|
* In-memory records are not file-backed, so there is no public file URL to return.
|
|
@@ -59,5 +51,4 @@ export declare class KeyValueStoreBackend extends BaseClient implements storage.
|
|
|
59
51
|
setValue(record: storage.KeyValueStoreInputRecord): Promise<void>;
|
|
60
52
|
deleteValue(key: string): Promise<void>;
|
|
61
53
|
toKeyValueStoreInfo(): storage.KeyValueStoreInfo;
|
|
62
|
-
private updateTimestamps;
|
|
63
54
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { parseArgument, schemas } from '@crawlee/utils/internal';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
import { isStream, toBuffer } from '../utils.js';
|
|
4
5
|
import { BaseClient } from './common/base-client.js';
|
|
5
6
|
import mime from 'mime-types';
|
|
6
7
|
const DEFAULT_LOCAL_FILE_EXTENSION = 'bin';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const keySchema = z.string();
|
|
9
|
+
const inputRecordSchema = z.object({
|
|
10
|
+
key: z.string().min(1),
|
|
11
|
+
value: z.union([
|
|
12
|
+
z.null(),
|
|
13
|
+
z.string(),
|
|
14
|
+
z.number(),
|
|
15
|
+
z.instanceof(Buffer),
|
|
16
|
+
z.instanceof(ArrayBuffer),
|
|
17
|
+
schemas.typedArray,
|
|
18
|
+
// only checks the value is an actual object, not null, nor array
|
|
19
|
+
schemas.plainObject,
|
|
20
|
+
]),
|
|
21
|
+
contentType: z.string().min(1).optional(),
|
|
22
|
+
});
|
|
12
23
|
export class KeyValueStoreBackend extends BaseClient {
|
|
13
24
|
name;
|
|
14
25
|
/**
|
|
@@ -19,53 +30,31 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
19
30
|
createdAt = new Date();
|
|
20
31
|
accessedAt = new Date();
|
|
21
32
|
modifiedAt = new Date();
|
|
22
|
-
keyValueEntries = new Map();
|
|
23
|
-
storageBackend;
|
|
33
|
+
#keyValueEntries = new Map();
|
|
34
|
+
#storageBackend;
|
|
24
35
|
constructor(options) {
|
|
25
36
|
super(options.id ?? randomUUID());
|
|
26
37
|
this.name = options.name;
|
|
27
38
|
this.cacheKey = options.cacheKey ?? this.name ?? this.id;
|
|
28
|
-
this
|
|
39
|
+
this.#storageBackend = options.storageBackend;
|
|
29
40
|
}
|
|
30
41
|
async getMetadata() {
|
|
31
|
-
this
|
|
42
|
+
this.#updateTimestamps(false);
|
|
32
43
|
return this.toKeyValueStoreInfo();
|
|
33
44
|
}
|
|
34
45
|
async drop() {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const [oldBackend] = this.storageBackend.keyValueStoreBackendCache.splice(storeIndex, 1);
|
|
38
|
-
oldBackend.keyValueEntries.clear();
|
|
46
|
+
if (this.#storageBackend.evictBackend('KeyValueStore', this.id)) {
|
|
47
|
+
this.#keyValueEntries.clear();
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
50
|
async purge() {
|
|
42
|
-
this
|
|
43
|
-
this
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Purges every record except the run's input. Used by {@link MemoryStorageBackend.purge} for the
|
|
47
|
-
* default key-value store, mirroring `FileSystemStorageBackend`, which preserves `INPUT` (and its
|
|
48
|
-
* extension variants) when purging the default store. The in-memory key has no extension, so we
|
|
49
|
-
* preserve the bare `INPUT` key only.
|
|
50
|
-
*/
|
|
51
|
-
async purgeExceptInput() {
|
|
52
|
-
for (const key of this.keyValueEntries.keys()) {
|
|
53
|
-
if (key !== KEY_VALUE_STORE_INPUT_KEY) {
|
|
54
|
-
this.keyValueEntries.delete(key);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
this.updateTimestamps(true);
|
|
51
|
+
this.#keyValueEntries.clear();
|
|
52
|
+
this.#updateTimestamps(true);
|
|
58
53
|
}
|
|
59
54
|
async listKeys(options = {}) {
|
|
60
|
-
const { prefix, exclusiveStartKey, limit } =
|
|
61
|
-
.object({
|
|
62
|
-
prefix: s.string().optional(),
|
|
63
|
-
exclusiveStartKey: s.string().optional(),
|
|
64
|
-
limit: s.number().int().greaterThan(0).optional(),
|
|
65
|
-
})
|
|
66
|
-
.parse(options);
|
|
55
|
+
const { prefix, exclusiveStartKey, limit } = parseArgument(options, schemas.keyValueStoreListKeysOptions);
|
|
67
56
|
const items = [];
|
|
68
|
-
for (const record of this
|
|
57
|
+
for (const record of this.#keyValueEntries.values()) {
|
|
69
58
|
const size = Buffer.byteLength(record.value);
|
|
70
59
|
items.push({
|
|
71
60
|
key: record.key,
|
|
@@ -87,7 +76,7 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
87
76
|
const isTruncated = limit !== undefined && filteredItems.length > limit;
|
|
88
77
|
const pageItems = isTruncated ? filteredItems.slice(0, limit) : filteredItems;
|
|
89
78
|
const nextExclusiveStartKey = isTruncated ? pageItems[pageItems.length - 1].key : undefined;
|
|
90
|
-
this
|
|
79
|
+
this.#updateTimestamps(false);
|
|
91
80
|
return {
|
|
92
81
|
items: pageItems,
|
|
93
82
|
count: pageItems.length,
|
|
@@ -103,7 +92,7 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
103
92
|
* @param key The key of the record to generate the public URL for.
|
|
104
93
|
*/
|
|
105
94
|
async getPublicUrl(key) {
|
|
106
|
-
|
|
95
|
+
parseArgument(key, keySchema);
|
|
107
96
|
return undefined;
|
|
108
97
|
}
|
|
109
98
|
/**
|
|
@@ -113,12 +102,12 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
113
102
|
* @returns `true` if the record exists, `false` if it does not.
|
|
114
103
|
*/
|
|
115
104
|
async recordExists(key) {
|
|
116
|
-
|
|
117
|
-
return this
|
|
105
|
+
parseArgument(key, keySchema);
|
|
106
|
+
return this.#keyValueEntries.has(key);
|
|
118
107
|
}
|
|
119
108
|
async getValue(key) {
|
|
120
|
-
|
|
121
|
-
const entry = this
|
|
109
|
+
parseArgument(key, keySchema);
|
|
110
|
+
const entry = this.#keyValueEntries.get(key);
|
|
122
111
|
if (!entry) {
|
|
123
112
|
return undefined;
|
|
124
113
|
}
|
|
@@ -131,24 +120,11 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
131
120
|
// frontend treats it as "no content type" rather than a bogus value.
|
|
132
121
|
contentType: entry.contentType ?? (mime.contentType(entry.extension) || undefined),
|
|
133
122
|
};
|
|
134
|
-
this
|
|
123
|
+
this.#updateTimestamps(false);
|
|
135
124
|
return record;
|
|
136
125
|
}
|
|
137
126
|
async setValue(record) {
|
|
138
|
-
|
|
139
|
-
key: s.string().lengthGreaterThan(0),
|
|
140
|
-
value: s.union([
|
|
141
|
-
s.null(),
|
|
142
|
-
s.string(),
|
|
143
|
-
s.number(),
|
|
144
|
-
s.instance(Buffer),
|
|
145
|
-
s.instance(ArrayBuffer),
|
|
146
|
-
s.typedArray(),
|
|
147
|
-
// disabling validation will make shapeshift only check the object given is an actual object, not null, nor array
|
|
148
|
-
s.object({}).setValidationEnabled(false),
|
|
149
|
-
]),
|
|
150
|
-
contentType: s.string().lengthGreaterThan(0).optional(),
|
|
151
|
-
}).parse(record);
|
|
127
|
+
parseArgument(record, inputRecordSchema);
|
|
152
128
|
const { key } = record;
|
|
153
129
|
let { value } = record;
|
|
154
130
|
// The frontend (KeyValueStore codec) serializes the value and resolves its content type
|
|
@@ -169,20 +145,20 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
169
145
|
const normalizedValue = typeof value === 'string'
|
|
170
146
|
? Buffer.from(value, 'utf-8')
|
|
171
147
|
: toBuffer(value);
|
|
172
|
-
const
|
|
148
|
+
const normalizedRecord = {
|
|
173
149
|
extension,
|
|
174
150
|
key,
|
|
175
151
|
value: normalizedValue,
|
|
176
152
|
contentType,
|
|
177
153
|
};
|
|
178
|
-
this
|
|
179
|
-
this
|
|
154
|
+
this.#keyValueEntries.set(key, normalizedRecord);
|
|
155
|
+
this.#updateTimestamps(true);
|
|
180
156
|
}
|
|
181
157
|
async deleteValue(key) {
|
|
182
|
-
|
|
183
|
-
if (this
|
|
184
|
-
this
|
|
185
|
-
this
|
|
158
|
+
parseArgument(key, keySchema);
|
|
159
|
+
if (this.#keyValueEntries.has(key)) {
|
|
160
|
+
this.#keyValueEntries.delete(key);
|
|
161
|
+
this.#updateTimestamps(true);
|
|
186
162
|
}
|
|
187
163
|
}
|
|
188
164
|
toKeyValueStoreInfo() {
|
|
@@ -194,7 +170,7 @@ export class KeyValueStoreBackend extends BaseClient {
|
|
|
194
170
|
modifiedAt: this.modifiedAt,
|
|
195
171
|
};
|
|
196
172
|
}
|
|
197
|
-
updateTimestamps(hasBeenModified) {
|
|
173
|
+
#updateTimestamps(hasBeenModified) {
|
|
198
174
|
this.accessedAt = new Date();
|
|
199
175
|
if (hasBeenModified) {
|
|
200
176
|
this.modifiedAt = new Date();
|
|
@@ -22,6 +22,7 @@ export interface InternalRequest {
|
|
|
22
22
|
json: string;
|
|
23
23
|
}
|
|
24
24
|
export declare class RequestQueueBackend extends BaseClient implements storage.RequestQueueBackend {
|
|
25
|
+
#private;
|
|
25
26
|
name?: string;
|
|
26
27
|
/**
|
|
27
28
|
* The key used for cache lookup. For named storages, this equals the name. For alias (unnamed)
|
|
@@ -33,48 +34,10 @@ export declare class RequestQueueBackend extends BaseClient implements storage.R
|
|
|
33
34
|
modifiedAt: Date;
|
|
34
35
|
handledRequestCount: number;
|
|
35
36
|
pendingRequestCount: number;
|
|
36
|
-
/**
|
|
37
|
-
* Serializes every operation that reads-then-writes this backend's shared queue state — the
|
|
38
|
-
* `requests` map, the `forefrontRequestIds` array, the `inProgressRequestIds` set and the request
|
|
39
|
-
* counts. Those mutations span `await` points, so without this mutex a concurrent operation could
|
|
40
|
-
* interleave and corrupt them (e.g. a head scan pruning `forefrontRequestIds` while
|
|
41
|
-
* `addBatchOfRequests` pushes to it). Held by every mutating method as well as by `isEmpty`/
|
|
42
|
-
* `isFinished`, whose head scan also prunes `forefrontRequestIds`.
|
|
43
|
-
*/
|
|
44
|
-
private readonly queueStateMutex;
|
|
45
|
-
private forefrontRequestIds;
|
|
46
|
-
/**
|
|
47
|
-
* IDs of requests currently fetched but not yet handled or reclaimed. A request in this set is
|
|
48
|
-
* "in progress" and will not be handed out again by {@link fetchNextRequest}.
|
|
49
|
-
*
|
|
50
|
-
* Unlike the file-system / platform clients, the in-memory queue lives entirely within a single
|
|
51
|
-
* process and is never shared with another consumer, so there is no need for an expiring,
|
|
52
|
-
* cross-process-visible lock — tracking in-progress requests in this set is enough.
|
|
53
|
-
*/
|
|
54
|
-
private readonly inProgressRequestIds;
|
|
55
|
-
private readonly requests;
|
|
56
|
-
private readonly storageBackend;
|
|
57
37
|
constructor(options: RequestQueueBackendOptions);
|
|
58
38
|
getMetadata(): Promise<storage.RequestQueueInfo>;
|
|
59
39
|
drop(): Promise<void>;
|
|
60
40
|
purge(): Promise<void>;
|
|
61
|
-
private requestKeyIterator;
|
|
62
|
-
/**
|
|
63
|
-
* Scans the queue and returns the pending head — requests that are neither handled nor currently
|
|
64
|
-
* in progress — ordered by `orderNo`, deduplicated.
|
|
65
|
-
*
|
|
66
|
-
* When `detectInProgressRequests` is set, the result also carries an `hasInProgressRequests` flag
|
|
67
|
-
* telling whether any unhandled-but-in-progress request was skipped along the way. It lets
|
|
68
|
-
* {@link isFinished} distinguish "no work left at all" from "work remains, but it is currently being
|
|
69
|
-
* processed". Without it, a consumer with concurrency could consider the queue finished and shut the
|
|
70
|
-
* crawler down while it is still handling the last requests.
|
|
71
|
-
*
|
|
72
|
-
* Computing the flag is expensive: because an in-progress request may sit anywhere in the queue, it
|
|
73
|
-
* forces a scan of every pending entry even when only `limit` items are wanted. Callers that only
|
|
74
|
-
* need the head (e.g. {@link fetchNextRequest}, {@link isEmpty}) leave it off so the scan can stop as
|
|
75
|
-
* soon as the page is filled, keeping those calls O(head) instead of O(N).
|
|
76
|
-
*/
|
|
77
|
-
private listPendingHead;
|
|
78
41
|
fetchNextRequest(): Promise<storage.UpdateRequestSchema | undefined>;
|
|
79
42
|
addBatchOfRequests(requests: storage.RequestSchema[], options?: storage.RequestQueueOperationOptions): Promise<storage.BatchAddRequestsResult>;
|
|
80
43
|
getRequest(uniqueKey: string): Promise<storage.UpdateRequestSchema | undefined>;
|
|
@@ -89,8 +52,4 @@ export declare class RequestQueueBackend extends BaseClient implements storage.R
|
|
|
89
52
|
*/
|
|
90
53
|
listItems(): Promise<storage.UpdateRequestSchema[]>;
|
|
91
54
|
toRequestQueueInfo(): storage.RequestQueueInfo;
|
|
92
|
-
private updateTimestamps;
|
|
93
|
-
private _jsonToRequest;
|
|
94
|
-
private _createInternalRequest;
|
|
95
|
-
private _calculateOrderNo;
|
|
96
55
|
}
|