apify 3.7.3-beta.9 → 4.0.0-beta.13
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/dist/actor.d.ts +19 -4
- package/dist/actor.js +207 -239
- package/dist/apify_storage_client.d.ts +54 -0
- package/dist/apify_storage_client.js +152 -0
- package/dist/charging.js +45 -122
- package/dist/configuration.d.ts +79 -141
- package/dist/configuration.js +117 -171
- package/dist/index.js +8 -22
- package/dist/input-schemas.js +12 -18
- package/dist/key_value_store.d.ts +8 -3
- package/dist/key_value_store.js +22 -21
- package/dist/platform_event_manager.d.ts +0 -5
- package/dist/platform_event_manager.js +18 -34
- package/dist/proxy_configuration.d.ts +26 -55
- package/dist/proxy_configuration.js +80 -174
- package/dist/storage.d.ts +6 -4
- package/dist/storage.js +17 -17
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +39 -23
- package/package.json +16 -15
- package/dist/index.mjs +0 -19
- package/dist/patched_apify_client.d.ts +0 -25
- package/dist/patched_apify_client.js +0 -70
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import type { CreateDatasetClientOptions, CreateKeyValueStoreClientOptions, CreateRequestQueueClientOptions, DatasetClient, KeyValueStoreClient, RequestQueueClient, StorageClient } from '@crawlee/types';
|
|
3
|
+
import type { ApifyClient } from 'apify-client';
|
|
4
|
+
import { type ChargeResult, type ChargingManager } from './charging.js';
|
|
5
|
+
import type { Configuration } from './configuration.js';
|
|
6
|
+
type StorageType = 'Dataset' | 'KeyValueStore' | 'RequestQueue';
|
|
7
|
+
/** Marks a dataset client whose `pushItems` charges for pay-per-event. @internal */
|
|
8
|
+
export declare const USES_PUSH_DATA_INTERCEPTION: unique symbol;
|
|
9
|
+
/**
|
|
10
|
+
* Context of a single `Actor.pushData()` call, shared with the intercepted
|
|
11
|
+
* `pushItems()` calls so they can (1) know which event to charge and
|
|
12
|
+
* (2) aggregate the {@link ChargeResult} across the multiple `pushItems()`
|
|
13
|
+
* calls a single `pushData()` may trigger (Crawlee batches large pushes).
|
|
14
|
+
*/
|
|
15
|
+
export interface PpeAwarePushDataContext {
|
|
16
|
+
eventName: string | undefined;
|
|
17
|
+
chargeResult?: ChargeResult;
|
|
18
|
+
}
|
|
19
|
+
export declare const pushDataChargingContext: AsyncLocalStorage<PpeAwarePushDataContext>;
|
|
20
|
+
/**
|
|
21
|
+
* Bridges `apify-client`'s synchronous resource accessors (`dataset(id)`,
|
|
22
|
+
* `keyValueStore(id)`, `requestQueue(id, options?)`) to crawlee v4's
|
|
23
|
+
* `StorageClient` interface (async factory methods accepting either an `id`
|
|
24
|
+
* or a `name`).
|
|
25
|
+
*
|
|
26
|
+
* For the run's default dataset it transparently swaps in a charging-aware
|
|
27
|
+
* dataset client (pay-per-event on `Actor.pushData()`), provided a charging
|
|
28
|
+
* manager is supplied and a default-dataset-item price is configured.
|
|
29
|
+
*
|
|
30
|
+
* `storageExists()` lets `Dataset.open(idOrName)` resolve a string to an id
|
|
31
|
+
* first (when one exists on the platform) and fall back to a name otherwise —
|
|
32
|
+
* otherwise crawlee's `resolveStorageIdentifier` treats every string as a name
|
|
33
|
+
* and the SDK would silently create a new storage named like the passed id.
|
|
34
|
+
*/
|
|
35
|
+
export declare class ApifyStorageClient implements StorageClient {
|
|
36
|
+
private readonly client;
|
|
37
|
+
private readonly config?;
|
|
38
|
+
private readonly getChargingManager?;
|
|
39
|
+
constructor(client: ApifyClient, config?: Configuration | undefined, getChargingManager?: (() => ChargingManager) | undefined);
|
|
40
|
+
storageExists(id: string, type: StorageType): Promise<boolean>;
|
|
41
|
+
createDatasetClient(options?: CreateDatasetClientOptions): Promise<DatasetClient>;
|
|
42
|
+
createKeyValueStoreClient(options?: CreateKeyValueStoreClientOptions): Promise<KeyValueStoreClient>;
|
|
43
|
+
createRequestQueueClient(options?: CreateRequestQueueClientOptions): Promise<RequestQueueClient>;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a charging-aware dataset client when `id` is the run's default
|
|
46
|
+
* dataset and a default-dataset-item price is configured; otherwise
|
|
47
|
+
* `undefined` (caller uses the plain client).
|
|
48
|
+
*/
|
|
49
|
+
private chargingDatasetClient;
|
|
50
|
+
private resolveId;
|
|
51
|
+
private resourceClient;
|
|
52
|
+
private collectionClient;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/* eslint-disable max-classes-per-file */
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
import { DatasetClient as ApifyDatasetClient } from 'apify-client';
|
|
4
|
+
import { DEFAULT_DATASET_ITEM_EVENT, mergeChargeResults, pushDataAndCharge, } from './charging.js';
|
|
5
|
+
const DEFAULT_ID_CONFIG_KEY = {
|
|
6
|
+
Dataset: 'defaultDatasetId',
|
|
7
|
+
KeyValueStore: 'defaultKeyValueStoreId',
|
|
8
|
+
RequestQueue: 'defaultRequestQueueId',
|
|
9
|
+
};
|
|
10
|
+
/** Marks a dataset client whose `pushItems` charges for pay-per-event. @internal */
|
|
11
|
+
export const USES_PUSH_DATA_INTERCEPTION = Symbol('apify:uses-push-data-interception');
|
|
12
|
+
export const pushDataChargingContext = new AsyncLocalStorage();
|
|
13
|
+
/**
|
|
14
|
+
* Default `DatasetClient` that charges for pushed items (pay-per-event). Used
|
|
15
|
+
* only for the run's default dataset when a `apify-default-dataset-item` price
|
|
16
|
+
* is configured; for everything else the plain `apify-client` dataset client is
|
|
17
|
+
* used.
|
|
18
|
+
*/
|
|
19
|
+
class PpeAwareDatasetClient extends ApifyDatasetClient {
|
|
20
|
+
getChargingManager;
|
|
21
|
+
constructor(options, getChargingManager) {
|
|
22
|
+
super(options);
|
|
23
|
+
this.getChargingManager = getChargingManager;
|
|
24
|
+
}
|
|
25
|
+
normalizeItems(items) {
|
|
26
|
+
if (typeof items === 'string') {
|
|
27
|
+
const parsed = JSON.parse(items);
|
|
28
|
+
return Array.isArray(parsed) ? parsed : [parsed];
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(items)) {
|
|
31
|
+
return items.flatMap((item) => typeof item === 'string' ? JSON.parse(item) : item);
|
|
32
|
+
}
|
|
33
|
+
return [items];
|
|
34
|
+
}
|
|
35
|
+
async pushItems(items) {
|
|
36
|
+
const context = pushDataChargingContext.getStore();
|
|
37
|
+
// A single JSON string may encode multiple items (e.g. '[{...},{...}]'),
|
|
38
|
+
// which the charging logic would miscount — parse strings into arrays so
|
|
39
|
+
// each logical item is counted individually.
|
|
40
|
+
const normalizedItems = this.normalizeItems(items);
|
|
41
|
+
const result = await pushDataAndCharge({
|
|
42
|
+
chargingManager: this.getChargingManager(),
|
|
43
|
+
items: normalizedItems,
|
|
44
|
+
eventName: context?.eventName,
|
|
45
|
+
isDefaultDataset: true,
|
|
46
|
+
// stringify for faster validation in the Apify client
|
|
47
|
+
pushFn: async (limitedItems) => super.pushItems(JSON.stringify(limitedItems)),
|
|
48
|
+
});
|
|
49
|
+
if (!context)
|
|
50
|
+
return;
|
|
51
|
+
// One `Actor.pushData()` may map to several `pushItems()` calls — aggregate.
|
|
52
|
+
context.chargeResult =
|
|
53
|
+
context.chargeResult === undefined ? result : mergeChargeResults(context.chargeResult, result);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Bridges `apify-client`'s synchronous resource accessors (`dataset(id)`,
|
|
58
|
+
* `keyValueStore(id)`, `requestQueue(id, options?)`) to crawlee v4's
|
|
59
|
+
* `StorageClient` interface (async factory methods accepting either an `id`
|
|
60
|
+
* or a `name`).
|
|
61
|
+
*
|
|
62
|
+
* For the run's default dataset it transparently swaps in a charging-aware
|
|
63
|
+
* dataset client (pay-per-event on `Actor.pushData()`), provided a charging
|
|
64
|
+
* manager is supplied and a default-dataset-item price is configured.
|
|
65
|
+
*
|
|
66
|
+
* `storageExists()` lets `Dataset.open(idOrName)` resolve a string to an id
|
|
67
|
+
* first (when one exists on the platform) and fall back to a name otherwise —
|
|
68
|
+
* otherwise crawlee's `resolveStorageIdentifier` treats every string as a name
|
|
69
|
+
* and the SDK would silently create a new storage named like the passed id.
|
|
70
|
+
*/
|
|
71
|
+
export class ApifyStorageClient {
|
|
72
|
+
client;
|
|
73
|
+
config;
|
|
74
|
+
getChargingManager;
|
|
75
|
+
constructor(client, config, getChargingManager) {
|
|
76
|
+
this.client = client;
|
|
77
|
+
this.config = config;
|
|
78
|
+
this.getChargingManager = getChargingManager;
|
|
79
|
+
}
|
|
80
|
+
async storageExists(id, type) {
|
|
81
|
+
// Apify's `GET /v2/{kind}/{idOrName}` matches by either id or name;
|
|
82
|
+
// confirm it was an *id* match so crawlee can fall through to `{ name }`.
|
|
83
|
+
const info = await this.resourceClient(id, type).get();
|
|
84
|
+
return info?.id === id;
|
|
85
|
+
}
|
|
86
|
+
async createDatasetClient(options) {
|
|
87
|
+
const id = await this.resolveId(options, 'Dataset');
|
|
88
|
+
const datasetClient = this.chargingDatasetClient(id) ?? this.client.dataset(id);
|
|
89
|
+
// apify-client's resource clients overlap with `@crawlee/types`' shapes
|
|
90
|
+
// but don't implement the v4-added members (`getMetadata`,
|
|
91
|
+
// `getRecordPublicUrl`), so cast through.
|
|
92
|
+
return datasetClient;
|
|
93
|
+
}
|
|
94
|
+
async createKeyValueStoreClient(options) {
|
|
95
|
+
const id = await this.resolveId(options, 'KeyValueStore');
|
|
96
|
+
return this.client.keyValueStore(id);
|
|
97
|
+
}
|
|
98
|
+
async createRequestQueueClient(options) {
|
|
99
|
+
const id = await this.resolveId(options, 'RequestQueue');
|
|
100
|
+
return this.client.requestQueue(id, options?.clientKey ? { clientKey: options.clientKey } : undefined);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Returns a charging-aware dataset client when `id` is the run's default
|
|
104
|
+
* dataset and a default-dataset-item price is configured; otherwise
|
|
105
|
+
* `undefined` (caller uses the plain client).
|
|
106
|
+
*/
|
|
107
|
+
chargingDatasetClient(id) {
|
|
108
|
+
const { getChargingManager } = this;
|
|
109
|
+
if (!getChargingManager)
|
|
110
|
+
return undefined;
|
|
111
|
+
if (id !== this.config?.defaultDatasetId)
|
|
112
|
+
return undefined;
|
|
113
|
+
const hasDefaultDatasetItemEvent = DEFAULT_DATASET_ITEM_EVENT in getChargingManager().getPricingInfo().perEventPrices;
|
|
114
|
+
if (!hasDefaultDatasetItemEvent)
|
|
115
|
+
return undefined;
|
|
116
|
+
const datasetClient = new PpeAwareDatasetClient({
|
|
117
|
+
id,
|
|
118
|
+
baseUrl: this.client.baseUrl,
|
|
119
|
+
publicBaseUrl: this.client.publicBaseUrl,
|
|
120
|
+
apifyClient: this.client,
|
|
121
|
+
httpClient: this.client.httpClient,
|
|
122
|
+
}, getChargingManager);
|
|
123
|
+
Object.assign(datasetClient, {
|
|
124
|
+
[USES_PUSH_DATA_INTERCEPTION]: true,
|
|
125
|
+
});
|
|
126
|
+
return datasetClient;
|
|
127
|
+
}
|
|
128
|
+
async resolveId(options, type) {
|
|
129
|
+
if (options?.id)
|
|
130
|
+
return options.id;
|
|
131
|
+
if (options?.name) {
|
|
132
|
+
return (await this.collectionClient(type).getOrCreate(options.name)).id;
|
|
133
|
+
}
|
|
134
|
+
// No id/name (crawlee's `__default__` alias): use the default storage
|
|
135
|
+
// id from the run's environment. apify-client rejects an empty id.
|
|
136
|
+
return this.config?.[DEFAULT_ID_CONFIG_KEY[type]] ?? '';
|
|
137
|
+
}
|
|
138
|
+
resourceClient(id, type) {
|
|
139
|
+
if (type === 'Dataset')
|
|
140
|
+
return this.client.dataset(id);
|
|
141
|
+
if (type === 'KeyValueStore')
|
|
142
|
+
return this.client.keyValueStore(id);
|
|
143
|
+
return this.client.requestQueue(id);
|
|
144
|
+
}
|
|
145
|
+
collectionClient(type) {
|
|
146
|
+
if (type === 'Dataset')
|
|
147
|
+
return this.client.datasets();
|
|
148
|
+
if (type === 'KeyValueStore')
|
|
149
|
+
return this.client.keyValueStores();
|
|
150
|
+
return this.client.requestQueues();
|
|
151
|
+
}
|
|
152
|
+
}
|
package/dist/charging.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.pushDataAndCharge = pushDataAndCharge;
|
|
6
|
-
const tslib_1 = require("tslib");
|
|
7
|
-
const core_1 = require("@crawlee/core");
|
|
8
|
-
const log_1 = tslib_1.__importDefault(require("@apify/log"));
|
|
9
|
-
exports.DEFAULT_DATASET_ITEM_EVENT = 'apify-default-dataset-item';
|
|
10
|
-
function mergeChargeResults(a, b) {
|
|
1
|
+
import { Dataset, KeyValueStore } from '@crawlee/core';
|
|
2
|
+
import log from '@apify/log';
|
|
3
|
+
export const DEFAULT_DATASET_ITEM_EVENT = 'apify-default-dataset-item';
|
|
4
|
+
export function mergeChargeResults(a, b) {
|
|
11
5
|
return {
|
|
12
6
|
eventChargeLimitReached: a.eventChargeLimitReached || b.eventChargeLimitReached,
|
|
13
7
|
chargedCount: a.chargedCount + b.chargedCount,
|
|
@@ -20,108 +14,39 @@ function mergeChargeResults(a, b) {
|
|
|
20
14
|
/**
|
|
21
15
|
* Handles pay-per-event charging.
|
|
22
16
|
*/
|
|
23
|
-
class ChargingManager {
|
|
17
|
+
export class ChargingManager {
|
|
18
|
+
configuration;
|
|
19
|
+
LOCAL_CHARGING_LOG_DATASET_NAME = 'charging_log';
|
|
20
|
+
PLATFORM_CHARGING_LOG_DATASET_ID_KEY = 'CHARGING_LOG_DATASET_ID';
|
|
21
|
+
maxTotalChargeUsd;
|
|
22
|
+
isAtHome;
|
|
23
|
+
actorRunId;
|
|
24
|
+
pricingModel;
|
|
25
|
+
purgeChargingLogDataset;
|
|
26
|
+
useChargingLogDataset;
|
|
27
|
+
notPpeWarningPrinted = false;
|
|
28
|
+
pricingInfo = {};
|
|
29
|
+
chargingState;
|
|
30
|
+
chargingLogDataset;
|
|
31
|
+
apifyClient;
|
|
24
32
|
constructor(configuration, apifyClient) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Object.defineProperty(this, "LOCAL_CHARGING_LOG_DATASET_NAME", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
configurable: true,
|
|
34
|
-
writable: true,
|
|
35
|
-
value: 'charging_log'
|
|
36
|
-
});
|
|
37
|
-
Object.defineProperty(this, "PLATFORM_CHARGING_LOG_DATASET_ID_KEY", {
|
|
38
|
-
enumerable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
writable: true,
|
|
41
|
-
value: 'CHARGING_LOG_DATASET_ID'
|
|
42
|
-
});
|
|
43
|
-
Object.defineProperty(this, "maxTotalChargeUsd", {
|
|
44
|
-
enumerable: true,
|
|
45
|
-
configurable: true,
|
|
46
|
-
writable: true,
|
|
47
|
-
value: void 0
|
|
48
|
-
});
|
|
49
|
-
Object.defineProperty(this, "isAtHome", {
|
|
50
|
-
enumerable: true,
|
|
51
|
-
configurable: true,
|
|
52
|
-
writable: true,
|
|
53
|
-
value: void 0
|
|
54
|
-
});
|
|
55
|
-
Object.defineProperty(this, "actorRunId", {
|
|
56
|
-
enumerable: true,
|
|
57
|
-
configurable: true,
|
|
58
|
-
writable: true,
|
|
59
|
-
value: void 0
|
|
60
|
-
});
|
|
61
|
-
Object.defineProperty(this, "pricingModel", {
|
|
62
|
-
enumerable: true,
|
|
63
|
-
configurable: true,
|
|
64
|
-
writable: true,
|
|
65
|
-
value: void 0
|
|
66
|
-
});
|
|
67
|
-
Object.defineProperty(this, "purgeChargingLogDataset", {
|
|
68
|
-
enumerable: true,
|
|
69
|
-
configurable: true,
|
|
70
|
-
writable: true,
|
|
71
|
-
value: void 0
|
|
72
|
-
});
|
|
73
|
-
Object.defineProperty(this, "useChargingLogDataset", {
|
|
74
|
-
enumerable: true,
|
|
75
|
-
configurable: true,
|
|
76
|
-
writable: true,
|
|
77
|
-
value: void 0
|
|
78
|
-
});
|
|
79
|
-
Object.defineProperty(this, "notPpeWarningPrinted", {
|
|
80
|
-
enumerable: true,
|
|
81
|
-
configurable: true,
|
|
82
|
-
writable: true,
|
|
83
|
-
value: false
|
|
84
|
-
});
|
|
85
|
-
Object.defineProperty(this, "pricingInfo", {
|
|
86
|
-
enumerable: true,
|
|
87
|
-
configurable: true,
|
|
88
|
-
writable: true,
|
|
89
|
-
value: {}
|
|
90
|
-
});
|
|
91
|
-
Object.defineProperty(this, "chargingState", {
|
|
92
|
-
enumerable: true,
|
|
93
|
-
configurable: true,
|
|
94
|
-
writable: true,
|
|
95
|
-
value: void 0
|
|
96
|
-
});
|
|
97
|
-
Object.defineProperty(this, "chargingLogDataset", {
|
|
98
|
-
enumerable: true,
|
|
99
|
-
configurable: true,
|
|
100
|
-
writable: true,
|
|
101
|
-
value: void 0
|
|
102
|
-
});
|
|
103
|
-
Object.defineProperty(this, "apifyClient", {
|
|
104
|
-
enumerable: true,
|
|
105
|
-
configurable: true,
|
|
106
|
-
writable: true,
|
|
107
|
-
value: void 0
|
|
108
|
-
});
|
|
109
|
-
this.maxTotalChargeUsd = configuration.get('maxTotalChargeUsd') || Infinity; // convert `0` to `Infinity` in case the value is an empty string
|
|
110
|
-
this.isAtHome = configuration.get('isAtHome');
|
|
111
|
-
this.actorRunId = configuration.get('actorRunId');
|
|
112
|
-
this.purgeChargingLogDataset = configuration.get('purgeOnStart');
|
|
113
|
-
this.useChargingLogDataset = configuration.get('useChargingLogDataset');
|
|
33
|
+
this.configuration = configuration;
|
|
34
|
+
this.maxTotalChargeUsd = configuration.maxTotalChargeUsd || Infinity; // convert `0` to `Infinity` in case the value is an empty string
|
|
35
|
+
this.isAtHome = configuration.isAtHome;
|
|
36
|
+
this.actorRunId = configuration.actorRunId;
|
|
37
|
+
this.purgeChargingLogDataset = configuration.purgeOnStart;
|
|
38
|
+
this.useChargingLogDataset = configuration.useChargingLogDataset;
|
|
114
39
|
this.apifyClient = apifyClient;
|
|
115
40
|
}
|
|
116
41
|
get isPayPerEvent() {
|
|
117
42
|
return this.pricingModel === 'PAY_PER_EVENT';
|
|
118
43
|
}
|
|
119
44
|
async fetchPricingInfo() {
|
|
120
|
-
if (this.configuration.
|
|
45
|
+
if (this.configuration.actorPricingInfo && this.configuration.chargedEventCounts) {
|
|
121
46
|
return {
|
|
122
|
-
pricingInfo: JSON.parse(this.configuration.
|
|
123
|
-
chargedEventCounts: JSON.parse(this.configuration.
|
|
124
|
-
maxTotalChargeUsd: this.configuration.
|
|
47
|
+
pricingInfo: JSON.parse(this.configuration.actorPricingInfo),
|
|
48
|
+
chargedEventCounts: JSON.parse(this.configuration.chargedEventCounts),
|
|
49
|
+
maxTotalChargeUsd: this.configuration.maxTotalChargeUsd || Infinity,
|
|
125
50
|
};
|
|
126
51
|
}
|
|
127
52
|
if (this.isAtHome) {
|
|
@@ -141,7 +66,7 @@ class ChargingManager {
|
|
|
141
66
|
return {
|
|
142
67
|
pricingInfo: undefined,
|
|
143
68
|
chargedEventCounts: {},
|
|
144
|
-
maxTotalChargeUsd: this.configuration.
|
|
69
|
+
maxTotalChargeUsd: this.configuration.maxTotalChargeUsd || Infinity,
|
|
145
70
|
};
|
|
146
71
|
}
|
|
147
72
|
/**
|
|
@@ -152,18 +77,18 @@ class ChargingManager {
|
|
|
152
77
|
if (this.useChargingLogDataset && this.isAtHome) {
|
|
153
78
|
throw new Error('Using the ACTOR_USE_CHARGING_LOG_DATASET environment variable is only supported in a local development environment');
|
|
154
79
|
}
|
|
155
|
-
if (this.configuration.
|
|
80
|
+
if (this.configuration.testPayPerEvent) {
|
|
156
81
|
if (this.isAtHome) {
|
|
157
82
|
throw new Error('Using the ACTOR_TEST_PAY_PER_EVENT environment variable is only supported in a local development environment');
|
|
158
83
|
}
|
|
159
84
|
}
|
|
160
85
|
// Retrieve pricing information
|
|
161
86
|
const { pricingInfo, chargedEventCounts, maxTotalChargeUsd } = await this.fetchPricingInfo();
|
|
162
|
-
if (this.configuration.
|
|
87
|
+
if (this.configuration.testPayPerEvent) {
|
|
163
88
|
this.pricingModel = 'PAY_PER_EVENT';
|
|
164
89
|
}
|
|
165
90
|
else {
|
|
166
|
-
this.pricingModel
|
|
91
|
+
this.pricingModel ??= pricingInfo?.pricingModel;
|
|
167
92
|
}
|
|
168
93
|
// Load per-event pricing information
|
|
169
94
|
if (pricingInfo?.pricingModel === 'PAY_PER_EVENT') {
|
|
@@ -188,18 +113,18 @@ class ChargingManager {
|
|
|
188
113
|
// Set up charging log dataset
|
|
189
114
|
if (this.isAtHome) {
|
|
190
115
|
const datasetId = await this.ensureChargingLogDatasetOnPlatform();
|
|
191
|
-
this.chargingLogDataset = await
|
|
116
|
+
this.chargingLogDataset = await Dataset.open(datasetId);
|
|
192
117
|
}
|
|
193
118
|
else {
|
|
194
119
|
if (this.purgeChargingLogDataset) {
|
|
195
|
-
const dataset = await
|
|
120
|
+
const dataset = await Dataset.open(this.LOCAL_CHARGING_LOG_DATASET_NAME);
|
|
196
121
|
await dataset.drop();
|
|
197
122
|
}
|
|
198
|
-
this.chargingLogDataset = await
|
|
123
|
+
this.chargingLogDataset = await Dataset.open(this.LOCAL_CHARGING_LOG_DATASET_NAME);
|
|
199
124
|
}
|
|
200
125
|
}
|
|
201
126
|
async ensureChargingLogDatasetOnPlatform() {
|
|
202
|
-
const defaultStore = await
|
|
127
|
+
const defaultStore = await KeyValueStore.open();
|
|
203
128
|
const storedDatasetId = await defaultStore.getValue(this.PLATFORM_CHARGING_LOG_DATASET_ID_KEY);
|
|
204
129
|
if (storedDatasetId !== null) {
|
|
205
130
|
return storedDatasetId;
|
|
@@ -239,11 +164,10 @@ class ChargingManager {
|
|
|
239
164
|
* @param options The name of the event to charge for and the number of events to be charged.
|
|
240
165
|
*/
|
|
241
166
|
async charge({ eventName, count = 1 }) {
|
|
242
|
-
var _a;
|
|
243
167
|
const calculateChargeableWithinLimit = () => Object.fromEntries(Object.keys(this.pricingInfo).map((name) => [name, this.calculateMaxEventChargeCountWithinLimit(name)]));
|
|
244
168
|
if (!this.isPayPerEvent) {
|
|
245
169
|
if (!this.notPpeWarningPrinted) {
|
|
246
|
-
|
|
170
|
+
log.warning('Ignored attempt to charge for an event - the Actor does not use the pay-per-event pricing');
|
|
247
171
|
this.notPpeWarningPrinted = true;
|
|
248
172
|
}
|
|
249
173
|
return {
|
|
@@ -280,10 +204,10 @@ class ChargingManager {
|
|
|
280
204
|
price: this.isAtHome ? 0 : 1, // Use a nonzero price for local development so that the maximum budget can be reached
|
|
281
205
|
title: `Unknown event '${eventName}'`,
|
|
282
206
|
};
|
|
283
|
-
|
|
207
|
+
this.chargingState[eventName] ??= {
|
|
284
208
|
chargeCount: 0,
|
|
285
209
|
totalChargedAmount: 0,
|
|
286
|
-
}
|
|
210
|
+
};
|
|
287
211
|
this.chargingState[eventName].chargeCount += chargedCount;
|
|
288
212
|
this.chargingState[eventName].totalChargedAmount += chargedCount * pricingInfo.price;
|
|
289
213
|
/* END OF CRITICAL SECTION */
|
|
@@ -296,7 +220,7 @@ class ChargingManager {
|
|
|
296
220
|
await this.apifyClient.run(this.actorRunId).charge({ eventName, count: chargedCount });
|
|
297
221
|
}
|
|
298
222
|
else {
|
|
299
|
-
|
|
223
|
+
log.warning(`Attempting to charge for an unknown event '${eventName}'`);
|
|
300
224
|
}
|
|
301
225
|
}
|
|
302
226
|
const timestamp = new Date().toISOString();
|
|
@@ -311,7 +235,7 @@ class ChargingManager {
|
|
|
311
235
|
}
|
|
312
236
|
if (chargedCount < count) {
|
|
313
237
|
const subject = count === 1 ? 'instance' : 'instances';
|
|
314
|
-
|
|
238
|
+
log.info(`Charging ${count} ${subject} of '${eventName}' event would exceed maxTotalChargeUsd - only ${chargedCount} events were charged`);
|
|
315
239
|
}
|
|
316
240
|
return {
|
|
317
241
|
eventChargeLimitReached: this.calculateMaxEventChargeCountWithinLimit(eventName) <= 0,
|
|
@@ -387,7 +311,7 @@ class ChargingManager {
|
|
|
387
311
|
};
|
|
388
312
|
}
|
|
389
313
|
const itemPrice = ((eventName !== undefined ? this.calculateEventPrice(eventName) : undefined) ?? 0) +
|
|
390
|
-
((isDefaultDataset ? this.calculateEventPrice(
|
|
314
|
+
((isDefaultDataset ? this.calculateEventPrice(DEFAULT_DATASET_ITEM_EVENT) : undefined) ?? 0);
|
|
391
315
|
const maxChargedCount = itemPrice > 0 ? this.calculateMaxChargesByPrice(itemPrice) : Infinity;
|
|
392
316
|
const itemsToKeep = (() => {
|
|
393
317
|
if (maxChargedCount >= itemsArray.length) {
|
|
@@ -408,7 +332,7 @@ class ChargingManager {
|
|
|
408
332
|
eventsToCharge[eventName] = itemsToKeep;
|
|
409
333
|
}
|
|
410
334
|
if (isDefaultDataset && itemsToKeep > 0) {
|
|
411
|
-
eventsToCharge[
|
|
335
|
+
eventsToCharge[DEFAULT_DATASET_ITEM_EVENT] = itemsToKeep;
|
|
412
336
|
}
|
|
413
337
|
return {
|
|
414
338
|
limitedItems: itemsToKeep >= itemsArray.length ? itemsArray : itemsArray.slice(0, itemsToKeep),
|
|
@@ -416,7 +340,6 @@ class ChargingManager {
|
|
|
416
340
|
};
|
|
417
341
|
}
|
|
418
342
|
}
|
|
419
|
-
exports.ChargingManager = ChargingManager;
|
|
420
343
|
/**
|
|
421
344
|
* Helper for PPE-aware pushing of data to the dataset.
|
|
422
345
|
*
|
|
@@ -426,7 +349,7 @@ exports.ChargingManager = ChargingManager;
|
|
|
426
349
|
*
|
|
427
350
|
* @internal
|
|
428
351
|
*/
|
|
429
|
-
async function pushDataAndCharge({ chargingManager, items, eventName, isDefaultDataset, pushFn, }) {
|
|
352
|
+
export async function pushDataAndCharge({ chargingManager, items, eventName, isDefaultDataset, pushFn, }) {
|
|
430
353
|
const { limitedItems, eventsToCharge } = chargingManager.calculatePushDataLimits({
|
|
431
354
|
items,
|
|
432
355
|
eventName,
|