@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
package/storages/dataset.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { tryCancel } from '@apify/timeout';
|
|
3
3
|
import { Configuration } from '../configuration.js';
|
|
4
4
|
import { serviceLocator } from '../service_locator.js';
|
|
5
|
-
import {
|
|
5
|
+
import { parseArgument, schemas, validators } from '../validators.js';
|
|
6
|
+
import { activeStorageTransaction, rejectOperationInTransaction, snapshotValue } from './transaction.js';
|
|
6
7
|
import { KeyValueStore } from './key_value_store.js';
|
|
7
8
|
import { StorageStatsTracker } from './storage_stats.js';
|
|
8
9
|
import { resolveStorageIdentifier } from './storage_instance_manager.js';
|
|
9
10
|
import { createDualIterable, purgeDefaultStorages } from './utils.js';
|
|
11
|
+
const openOptionsSchema = z.strictObject({
|
|
12
|
+
configuration: z.instanceof(Configuration).optional(),
|
|
13
|
+
storageBackend: validators.storageBackend.optional(),
|
|
14
|
+
});
|
|
10
15
|
/** @internal */
|
|
11
16
|
export const DATASET_ITERATORS_DEFAULT_LIMIT = 10000;
|
|
12
17
|
/**
|
|
@@ -86,9 +91,9 @@ export class Dataset {
|
|
|
86
91
|
configuration;
|
|
87
92
|
id;
|
|
88
93
|
name;
|
|
94
|
+
// oxlint-disable-next-line crawlee/prefer-private-fields -- tests spy on the backend directly
|
|
89
95
|
backend;
|
|
90
|
-
|
|
91
|
-
statsTracker = new StorageStatsTracker({
|
|
96
|
+
#statsTracker = new StorageStatsTracker({
|
|
92
97
|
readCount: 0,
|
|
93
98
|
writeCount: 0,
|
|
94
99
|
});
|
|
@@ -100,14 +105,13 @@ export class Dataset {
|
|
|
100
105
|
this.id = options.metadata.id;
|
|
101
106
|
this.name = options.metadata.name;
|
|
102
107
|
this.backend = options.backend;
|
|
103
|
-
this.log = serviceLocator.getLogger().child({ prefix: 'Dataset' });
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
106
110
|
* Backend-independent usage counters tracked for this dataset (read / write operations issued to
|
|
107
111
|
* the underlying storage backend). Counted per backend call.
|
|
108
112
|
*/
|
|
109
113
|
get stats() {
|
|
110
|
-
return this
|
|
114
|
+
return this.#statsTracker.current;
|
|
111
115
|
}
|
|
112
116
|
/**
|
|
113
117
|
* Stores an object or an array of objects to the dataset.
|
|
@@ -121,24 +125,34 @@ export class Dataset {
|
|
|
121
125
|
* The objects must be serializable to JSON.
|
|
122
126
|
*/
|
|
123
127
|
async pushData(data) {
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
tryCancel();
|
|
129
|
+
const transaction = activeStorageTransaction();
|
|
130
|
+
parseArgument(data, schemas.anyObject);
|
|
126
131
|
// Normalize to array and validate each item
|
|
127
132
|
const items = Array.isArray(data) ? data : [data];
|
|
128
133
|
for (let i = 0; i < items.length; i++) {
|
|
129
134
|
assertJsonSerializable(items[i], i);
|
|
130
135
|
}
|
|
131
|
-
|
|
136
|
+
if (transaction) {
|
|
137
|
+
// One snapshot serves both the reads and the commit replay, so the two cannot disagree.
|
|
138
|
+
transaction.recordJournalEntry({
|
|
139
|
+
type: 'dataset',
|
|
140
|
+
participant: this,
|
|
141
|
+
storageId: this.id,
|
|
142
|
+
items: snapshotValue(items),
|
|
143
|
+
recordedAt: new Date(),
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
this.#statsTracker.add('writeCount');
|
|
132
148
|
await this.backend.pushData(items);
|
|
133
149
|
}
|
|
134
150
|
/**
|
|
135
151
|
* Returns {@link DatasetContent} object holding the items in the dataset based on the provided parameters.
|
|
136
152
|
*/
|
|
137
153
|
async getData(options = {}) {
|
|
138
|
-
checkStorageAccess();
|
|
139
154
|
try {
|
|
140
|
-
this
|
|
141
|
-
return await this.backend.getData(options);
|
|
155
|
+
return await this.#readPage(options);
|
|
142
156
|
}
|
|
143
157
|
catch (e) {
|
|
144
158
|
const error = e;
|
|
@@ -148,14 +162,95 @@ export class Dataset {
|
|
|
148
162
|
throw e;
|
|
149
163
|
}
|
|
150
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* The single transaction-aware page read all dataset read paths go through — both `getData()` and
|
|
167
|
+
* the private `fetchPages()`. Returns the real page concatenated with the current transaction's
|
|
168
|
+
* buffered items, with `offset` / `limit` / `desc` windowing applied across the concatenation.
|
|
169
|
+
*/
|
|
170
|
+
async #readPage(options) {
|
|
171
|
+
const buffered = this.#bufferedJournalEntries()?.flatMap((entry) => entry.items);
|
|
172
|
+
// Every branch below hits the backend exactly once.
|
|
173
|
+
this.#statsTracker.add('readCount');
|
|
174
|
+
if (!buffered?.length) {
|
|
175
|
+
return this.backend.getData(options);
|
|
176
|
+
}
|
|
177
|
+
const { offset = 0, limit, desc = false } = options;
|
|
178
|
+
if (!desc) {
|
|
179
|
+
const realPage = await this.backend.getData(options);
|
|
180
|
+
// Buffered items sit past `realPage.total`, so the window bounds must come from that - not
|
|
181
|
+
// from the page's shortfall, which `skipEmpty` produces without exhausting the real items.
|
|
182
|
+
const bufferedStart = Math.max(0, offset - realPage.total);
|
|
183
|
+
const bufferedEnd = limit === undefined ? buffered.length : Math.max(0, offset + limit - realPage.total);
|
|
184
|
+
const items = [...realPage.items, ...buffered.slice(bufferedStart, bufferedEnd)];
|
|
185
|
+
return {
|
|
186
|
+
items,
|
|
187
|
+
total: realPage.total + buffered.length,
|
|
188
|
+
offset,
|
|
189
|
+
// A caller that passed no limit wants everything, so the backend-reported `limit` is
|
|
190
|
+
// passed through - backends are free to report a page size or a sentinel there.
|
|
191
|
+
limit: limit ?? realPage.limit,
|
|
192
|
+
count: items.length,
|
|
193
|
+
desc,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Descending order: the buffered items are the newest, so they come first, reversed.
|
|
197
|
+
const reversedBuffer = [...buffered].reverse();
|
|
198
|
+
const fromBuffer = limit === undefined ? reversedBuffer.slice(offset) : reversedBuffer.slice(offset, offset + limit);
|
|
199
|
+
const needed = limit === undefined ? Infinity : limit - fromBuffer.length;
|
|
200
|
+
if (needed <= 0) {
|
|
201
|
+
// The whole window is served from the buffer; only the real total is missing.
|
|
202
|
+
const { itemCount } = await this.backend.getMetadata();
|
|
203
|
+
return {
|
|
204
|
+
items: fromBuffer,
|
|
205
|
+
total: itemCount + buffered.length,
|
|
206
|
+
offset,
|
|
207
|
+
limit: limit,
|
|
208
|
+
count: fromBuffer.length,
|
|
209
|
+
desc,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const realPage = await this.backend.getData({
|
|
213
|
+
...options,
|
|
214
|
+
offset: Math.max(0, offset - buffered.length),
|
|
215
|
+
...(limit === undefined ? {} : { limit: needed }),
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
items: [...fromBuffer, ...realPage.items],
|
|
219
|
+
total: realPage.total + buffered.length,
|
|
220
|
+
offset,
|
|
221
|
+
limit: limit ?? realPage.limit,
|
|
222
|
+
count: fromBuffer.length + realPage.items.length,
|
|
223
|
+
desc,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** The active transaction's buffered writes to this dataset, derived from its journal. */
|
|
227
|
+
#bufferedJournalEntries() {
|
|
228
|
+
const transaction = activeStorageTransaction();
|
|
229
|
+
return transaction?.journal.filter((entry) => entry.type === 'dataset' && entry.participant === this);
|
|
230
|
+
}
|
|
231
|
+
/** @internal */
|
|
232
|
+
async commitJournalEntries(entries) {
|
|
233
|
+
const items = [];
|
|
234
|
+
for (const entry of entries) {
|
|
235
|
+
if (entry.type === 'dataset') {
|
|
236
|
+
items.push(...entry.items);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// One backend call with all journaled items, in order - as close to atomic as the backend allows.
|
|
240
|
+
// Straight to the backend: the items were validated and snapshotted at write time.
|
|
241
|
+
if (items.length > 0) {
|
|
242
|
+
this.#statsTracker.add('writeCount');
|
|
243
|
+
await this.backend.pushData(items);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
151
246
|
/**
|
|
152
247
|
* Returns all the data from the dataset. This will iterate through the whole dataset
|
|
153
248
|
* via the `listItems()` client method, which gives you only paginated results.
|
|
154
249
|
*/
|
|
155
250
|
async export(options = {}) {
|
|
156
|
-
|
|
251
|
+
tryCancel();
|
|
157
252
|
const items = [];
|
|
158
|
-
for await (const page of this
|
|
253
|
+
for await (const page of this.#fetchPages(options)) {
|
|
159
254
|
items.push(...page.items);
|
|
160
255
|
}
|
|
161
256
|
return items;
|
|
@@ -179,6 +274,7 @@ export class Dataset {
|
|
|
179
274
|
const keys = options?.collectAllKeys
|
|
180
275
|
? Array.from(new Set(items.flatMap(Object.keys)))
|
|
181
276
|
: Object.keys(items[0]);
|
|
277
|
+
const { stringify } = await import('csv-stringify/sync');
|
|
182
278
|
const value = stringify([
|
|
183
279
|
keys,
|
|
184
280
|
...items.map((item) => {
|
|
@@ -219,7 +315,7 @@ export class Dataset {
|
|
|
219
315
|
* @param [options] An optional options object where you can provide the dataset and target KVS name.
|
|
220
316
|
*/
|
|
221
317
|
static async exportToJSON(key, options) {
|
|
222
|
-
|
|
318
|
+
tryCancel();
|
|
223
319
|
const dataset = await this.open(options?.fromDataset);
|
|
224
320
|
await dataset.exportToJSON(key, options);
|
|
225
321
|
}
|
|
@@ -230,7 +326,7 @@ export class Dataset {
|
|
|
230
326
|
* @param [options] An optional options object where you can provide the dataset and target KVS name.
|
|
231
327
|
*/
|
|
232
328
|
static async exportToCSV(key, options) {
|
|
233
|
-
|
|
329
|
+
tryCancel();
|
|
234
330
|
const dataset = await this.open(options?.fromDataset);
|
|
235
331
|
await dataset.exportToCSV(key, options);
|
|
236
332
|
}
|
|
@@ -252,8 +348,17 @@ export class Dataset {
|
|
|
252
348
|
* @throws If the underlying storage no longer exists (e.g. it was deleted externally).
|
|
253
349
|
*/
|
|
254
350
|
async getInfo() {
|
|
255
|
-
|
|
256
|
-
|
|
351
|
+
const buffered = this.#bufferedJournalEntries();
|
|
352
|
+
const metadata = await this.backend.getMetadata();
|
|
353
|
+
if (buffered?.length) {
|
|
354
|
+
const lastWriteAt = buffered[buffered.length - 1].recordedAt;
|
|
355
|
+
return {
|
|
356
|
+
...metadata,
|
|
357
|
+
itemCount: metadata.itemCount + buffered.reduce((sum, entry) => sum + entry.items.length, 0),
|
|
358
|
+
modifiedAt: metadata.modifiedAt > lastWriteAt ? metadata.modifiedAt : lastWriteAt,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
return metadata;
|
|
257
362
|
}
|
|
258
363
|
/**
|
|
259
364
|
* Iterates over dataset items, yielding each in turn to an `iteratee` function.
|
|
@@ -276,7 +381,7 @@ export class Dataset {
|
|
|
276
381
|
* @default 0
|
|
277
382
|
*/
|
|
278
383
|
async forEach(iteratee, options = {}, index = 0) {
|
|
279
|
-
|
|
384
|
+
tryCancel();
|
|
280
385
|
if (!options.offset)
|
|
281
386
|
options.offset = 0;
|
|
282
387
|
if (options.format && options.format !== 'json')
|
|
@@ -303,7 +408,7 @@ export class Dataset {
|
|
|
303
408
|
* @param [options] All `map()` parameters.
|
|
304
409
|
*/
|
|
305
410
|
async map(iteratee, options = {}) {
|
|
306
|
-
|
|
411
|
+
tryCancel();
|
|
307
412
|
const result = [];
|
|
308
413
|
await this.forEach(async (item, index) => {
|
|
309
414
|
const res = await iteratee(item, index);
|
|
@@ -312,7 +417,7 @@ export class Dataset {
|
|
|
312
417
|
return result;
|
|
313
418
|
}
|
|
314
419
|
async reduce(iteratee, memo, options = {}) {
|
|
315
|
-
|
|
420
|
+
tryCancel();
|
|
316
421
|
let currentMemo = memo;
|
|
317
422
|
const wrappedFunc = async (item, index) => {
|
|
318
423
|
if (index === 0 && currentMemo === undefined) {
|
|
@@ -327,16 +432,16 @@ export class Dataset {
|
|
|
327
432
|
await this.forEach(wrappedFunc, options);
|
|
328
433
|
return currentMemo;
|
|
329
434
|
}
|
|
330
|
-
async
|
|
435
|
+
async *#fetchEntryPages(options) {
|
|
331
436
|
let index = options.offset ?? 0;
|
|
332
|
-
for await (const page of this
|
|
437
|
+
for await (const page of this.#fetchPages(options)) {
|
|
333
438
|
yield {
|
|
334
439
|
...page,
|
|
335
440
|
items: page.items.map((item) => [index++, item]),
|
|
336
441
|
};
|
|
337
442
|
}
|
|
338
443
|
}
|
|
339
|
-
async
|
|
444
|
+
async *#fetchPages(options, pageSize = DATASET_ITERATORS_DEFAULT_LIMIT) {
|
|
340
445
|
let offset = options.offset ?? 0;
|
|
341
446
|
const totalLimit = options.limit;
|
|
342
447
|
let yielded = 0;
|
|
@@ -344,8 +449,7 @@ export class Dataset {
|
|
|
344
449
|
const fetchLimit = totalLimit !== undefined ? Math.min(pageSize, totalLimit - yielded) : pageSize;
|
|
345
450
|
if (fetchLimit <= 0)
|
|
346
451
|
break;
|
|
347
|
-
this
|
|
348
|
-
const page = await this.backend.getData({ ...options, offset, limit: fetchLimit });
|
|
452
|
+
const page = await this.#readPage({ ...options, offset, limit: fetchLimit });
|
|
349
453
|
yield page;
|
|
350
454
|
yielded += page.items.length;
|
|
351
455
|
if (page.items.length < fetchLimit || offset + page.items.length >= page.total)
|
|
@@ -377,9 +481,9 @@ export class Dataset {
|
|
|
377
481
|
* @param options Options for the iteration.
|
|
378
482
|
*/
|
|
379
483
|
values(options = {}) {
|
|
380
|
-
|
|
484
|
+
tryCancel();
|
|
381
485
|
return createDualIterable({
|
|
382
|
-
createPages: () => this
|
|
486
|
+
createPages: () => this.#fetchPages(options),
|
|
383
487
|
extractItems: (page) => page.items,
|
|
384
488
|
});
|
|
385
489
|
}
|
|
@@ -407,9 +511,9 @@ export class Dataset {
|
|
|
407
511
|
* @param options Options for the iteration.
|
|
408
512
|
*/
|
|
409
513
|
entries(options = {}) {
|
|
410
|
-
|
|
514
|
+
tryCancel();
|
|
411
515
|
return createDualIterable({
|
|
412
|
-
createPages: () => this
|
|
516
|
+
createPages: () => this.#fetchEntryPages(options),
|
|
413
517
|
extractItems: (page) => page.items,
|
|
414
518
|
});
|
|
415
519
|
}
|
|
@@ -433,10 +537,18 @@ export class Dataset {
|
|
|
433
537
|
* depending on the mode of operation.
|
|
434
538
|
*/
|
|
435
539
|
async drop() {
|
|
436
|
-
|
|
540
|
+
rejectOperationInTransaction('Dataset.drop()');
|
|
437
541
|
await this.backend.drop();
|
|
438
542
|
serviceLocator.getStorageInstanceManager().removeFromCache(this);
|
|
439
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* Removes all items from the dataset but keeps the dataset itself, along with its
|
|
546
|
+
* {@link Dataset.id|`id`} and {@link Dataset.name|`name`}.
|
|
547
|
+
*/
|
|
548
|
+
async purge() {
|
|
549
|
+
rejectOperationInTransaction('Dataset.purge()');
|
|
550
|
+
await this.backend.purge();
|
|
551
|
+
}
|
|
440
552
|
/**
|
|
441
553
|
* Opens a dataset and returns a promise resolving to an instance of the {@link Dataset} class.
|
|
442
554
|
*
|
|
@@ -453,14 +565,11 @@ export class Dataset {
|
|
|
453
565
|
* @param [options] Storage manager options.
|
|
454
566
|
*/
|
|
455
567
|
static async open(identifier, options = {}) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
})
|
|
461
|
-
options.configuration ??= Configuration.getGlobalConfiguration();
|
|
462
|
-
const storageBackend = options.storageBackend ?? serviceLocator.getStorageBackend();
|
|
463
|
-
await purgeDefaultStorages({ onlyPurgeOnce: true, storageBackend, configuration: options.configuration });
|
|
568
|
+
tryCancel();
|
|
569
|
+
const parsedOptions = parseArgument(options, openOptionsSchema);
|
|
570
|
+
const configuration = parsedOptions.configuration ?? Configuration.getGlobalConfiguration();
|
|
571
|
+
const storageBackend = parsedOptions.storageBackend ?? serviceLocator.getStorageBackend();
|
|
572
|
+
await purgeDefaultStorages({ onlyPurgeOnce: true, storageBackend, configuration });
|
|
464
573
|
const resolved = await resolveStorageIdentifier(identifier, storageBackend, 'Dataset');
|
|
465
574
|
return serviceLocator.getStorageInstanceManager().openStorage(this, {
|
|
466
575
|
...resolved,
|
package/storages/index.d.ts
CHANGED
|
@@ -5,9 +5,9 @@ export * from './request_list.js';
|
|
|
5
5
|
export type * from './request_loader.js';
|
|
6
6
|
export type * from './request_manager.js';
|
|
7
7
|
export * from './request_queue.js';
|
|
8
|
-
export
|
|
9
|
-
export
|
|
8
|
+
export type { DefaultStorageIdentifier, ExplicitStorageIdentifier, IStorage, StorageIdentifier, } from './storage_instance_manager.js';
|
|
9
|
+
export { StorageInstanceManager } from './storage_instance_manager.js';
|
|
10
|
+
export type { DatasetStats, KeyValueStoreStats, RequestQueueStats } from './storage_stats.js';
|
|
10
11
|
export * from './utils.js';
|
|
11
|
-
export * from './
|
|
12
|
-
export * from './sitemap_request_loader.js';
|
|
12
|
+
export * from './transaction.js';
|
|
13
13
|
export * from './request_manager_tandem.js';
|
package/storages/index.js
CHANGED
|
@@ -3,9 +3,7 @@ export * from './key_value_store.js';
|
|
|
3
3
|
export * from './key_value_store_codec.js';
|
|
4
4
|
export * from './request_list.js';
|
|
5
5
|
export * from './request_queue.js';
|
|
6
|
-
export
|
|
7
|
-
export * from './storage_stats.js';
|
|
6
|
+
export { StorageInstanceManager } from './storage_instance_manager.js';
|
|
8
7
|
export * from './utils.js';
|
|
9
|
-
export * from './
|
|
10
|
-
export * from './sitemap_request_loader.js';
|
|
8
|
+
export * from './transaction.js';
|
|
11
9
|
export * from './request_manager_tandem.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Awaitable, Dictionary, KeyValueStoreBackend, KeyValueStoreInfo } from '@crawlee/types';
|
|
2
2
|
import { Configuration } from '../configuration.js';
|
|
3
|
+
import type { JournalEntry } from './transaction.js';
|
|
3
4
|
import type { KeyValueStoreStats } from './storage_stats.js';
|
|
4
5
|
import type { StorageOpenOptions } from './utils.js';
|
|
5
6
|
import type { StorageIdentifier } from './storage_instance_manager.js';
|
|
@@ -19,8 +20,6 @@ import type { StorageIdentifier } from './storage_instance_manager.js';
|
|
|
19
20
|
* To access the default key-value store directly, you can use the
|
|
20
21
|
* {@link KeyValueStore.getValue} and {@link KeyValueStore.setValue} convenience functions.
|
|
21
22
|
*
|
|
22
|
-
* To access the input, you can also use the {@link KeyValueStore.getInput} convenience function.
|
|
23
|
-
*
|
|
24
23
|
* `KeyValueStore` stores its data on a local disk.
|
|
25
24
|
*
|
|
26
25
|
* If the `CRAWLEE_STORAGE_DIR` environment variable is set, the data is stored in
|
|
@@ -28,15 +27,14 @@ import type { StorageIdentifier } from './storage_instance_manager.js';
|
|
|
28
27
|
* ```
|
|
29
28
|
* {CRAWLEE_STORAGE_DIR}/key_value_stores/{STORE_ID}/{INDEX}.{EXT}
|
|
30
29
|
* ```
|
|
31
|
-
* Note that `{STORE_ID}` is the name or ID of the key-value store. The default key-value store has ID: `default
|
|
32
|
-
* unless you override it by setting the `CRAWLEE_DEFAULT_KEY_VALUE_STORE_ID` environment variable.
|
|
30
|
+
* Note that `{STORE_ID}` is the name or ID of the key-value store. The default key-value store has ID: `default`.
|
|
33
31
|
* The `{KEY}` is the key of the record and `{EXT}` corresponds to the MIME content type of the data value.
|
|
34
32
|
*
|
|
35
33
|
* **Example usage:**
|
|
36
34
|
*
|
|
37
35
|
* ```javascript
|
|
38
36
|
* // Get crawler input from the default key-value store.
|
|
39
|
-
* const input = await KeyValueStore.
|
|
37
|
+
* const input = await KeyValueStore.getValue('INPUT');
|
|
40
38
|
* // Get some value from the default key-value store.
|
|
41
39
|
* const otherValue = await KeyValueStore.getValue('my-key');
|
|
42
40
|
*
|
|
@@ -60,14 +58,11 @@ import type { StorageIdentifier } from './storage_instance_manager.js';
|
|
|
60
58
|
* @category Result Stores
|
|
61
59
|
*/
|
|
62
60
|
export declare class KeyValueStore {
|
|
61
|
+
#private;
|
|
63
62
|
readonly configuration: Configuration;
|
|
64
63
|
readonly id: string;
|
|
65
64
|
readonly name?: string;
|
|
66
|
-
|
|
67
|
-
private persistStateEventStarted;
|
|
68
|
-
/** Cache for persistent (auto-saved) values. When we try to set such value, the cache will be updated automatically. */
|
|
69
|
-
private readonly cache;
|
|
70
|
-
private readonly statsTracker;
|
|
65
|
+
readonly backend: KeyValueStoreBackend;
|
|
71
66
|
/**
|
|
72
67
|
* @internal
|
|
73
68
|
*/
|
|
@@ -176,9 +171,6 @@ export declare class KeyValueStore {
|
|
|
176
171
|
*/
|
|
177
172
|
recordExists(key: string): Promise<boolean>;
|
|
178
173
|
getAutoSavedValue<T extends Dictionary = Dictionary>(key: string, defaultValue?: T): Promise<T>;
|
|
179
|
-
private ensurePersistStateEvent;
|
|
180
|
-
private fetchKeyValuePages;
|
|
181
|
-
private fetchKeyPages;
|
|
182
174
|
/**
|
|
183
175
|
* Saves or deletes a record in the key-value store.
|
|
184
176
|
* The function returns a promise that resolves once the record has been saved or deleted.
|
|
@@ -223,11 +215,18 @@ export declare class KeyValueStore {
|
|
|
223
215
|
* @param [options] Record options.
|
|
224
216
|
*/
|
|
225
217
|
setValue<T>(key: string, value: T | null, options?: RecordOptions): Promise<void>;
|
|
218
|
+
/** @internal */
|
|
219
|
+
commitJournalEntries(entries: JournalEntry[]): Promise<void>;
|
|
226
220
|
/**
|
|
227
221
|
* Removes the key-value store either from the Apify cloud storage or from the local directory,
|
|
228
222
|
* depending on the mode of operation.
|
|
229
223
|
*/
|
|
230
224
|
drop(): Promise<void>;
|
|
225
|
+
/**
|
|
226
|
+
* Removes all records from the store but keeps the store itself, along with its
|
|
227
|
+
* {@link KeyValueStore.id|`id`} and {@link KeyValueStore.name|`name`}.
|
|
228
|
+
*/
|
|
229
|
+
purge(): Promise<void>;
|
|
231
230
|
/** @internal */
|
|
232
231
|
clearCache(): void;
|
|
233
232
|
/**
|
|
@@ -340,7 +339,9 @@ export declare class KeyValueStore {
|
|
|
340
339
|
/**
|
|
341
340
|
* Returns a file URL for the given key.
|
|
342
341
|
*
|
|
343
|
-
*
|
|
342
|
+
* The URL is derived from the key, so it is also returned for a record that does not exist (yet) —
|
|
343
|
+
* including one written earlier in an uncommitted storage transaction. Returns `undefined` only when
|
|
344
|
+
* the storage has no file URLs at all (e.g. the in-memory storage).
|
|
344
345
|
*
|
|
345
346
|
* @param key The key of the record to generate the public URL for.
|
|
346
347
|
*/
|
|
@@ -471,27 +472,6 @@ export declare class KeyValueStore {
|
|
|
471
472
|
* @ignore
|
|
472
473
|
*/
|
|
473
474
|
static setValue<T>(key: string, value: T | null, options?: RecordOptions): Promise<void>;
|
|
474
|
-
/**
|
|
475
|
-
* Gets the crawler input value from the default {@link KeyValueStore} associated with the current crawler run.
|
|
476
|
-
*
|
|
477
|
-
* The input is read from the default {@link KeyValueStore} under the configured input key
|
|
478
|
-
* (`CRAWLEE_INPUT_KEY`, default `INPUT`).
|
|
479
|
-
*
|
|
480
|
-
* Note that the `getInput()` function does not cache the value read from the key-value store.
|
|
481
|
-
* If you need to use the input multiple times in your crawler,
|
|
482
|
-
* it is far more efficient to read it once and store it locally.
|
|
483
|
-
*
|
|
484
|
-
* For more information, see {@link KeyValueStore.open}
|
|
485
|
-
* and {@link KeyValueStore.getValue}.
|
|
486
|
-
*
|
|
487
|
-
* @returns
|
|
488
|
-
* Returns a promise that resolves to an object, string
|
|
489
|
-
* or [`Buffer`](https://nodejs.org/api/buffer.html), depending
|
|
490
|
-
* on the MIME content type of the record, or `null`
|
|
491
|
-
* if the record is missing.
|
|
492
|
-
* @ignore
|
|
493
|
-
*/
|
|
494
|
-
static getInput<T = Dictionary | string | Buffer>(): Promise<T | null>;
|
|
495
475
|
}
|
|
496
476
|
/**
|
|
497
477
|
* User-function used in the {@link KeyValueStore.forEachKey} method.
|
|
@@ -507,6 +487,7 @@ export interface KeyConsumer {
|
|
|
507
487
|
size: number;
|
|
508
488
|
}): Awaitable<void>;
|
|
509
489
|
}
|
|
490
|
+
/** @internal */
|
|
510
491
|
export interface KeyValueStoreOptions {
|
|
511
492
|
/** Resolved metadata for the key-value store, as returned by the backend's `getMetadata()`. */
|
|
512
493
|
metadata: KeyValueStoreInfo;
|