@crawlee/core 4.0.0-beta.8 → 4.0.0-beta.81

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.
Files changed (257) hide show
  1. package/README.md +17 -13
  2. package/autoscaling/autoscaled_pool.d.ts +14 -15
  3. package/autoscaling/autoscaled_pool.js +37 -36
  4. package/autoscaling/client_load_signal.d.ts +25 -0
  5. package/autoscaling/client_load_signal.js +36 -0
  6. package/autoscaling/cpu_load_signal.d.ts +28 -0
  7. package/autoscaling/cpu_load_signal.js +24 -0
  8. package/autoscaling/event_loop_load_signal.d.ts +23 -0
  9. package/autoscaling/event_loop_load_signal.js +35 -0
  10. package/autoscaling/index.d.ts +5 -1
  11. package/autoscaling/index.js +5 -1
  12. package/autoscaling/load_signal.d.ts +99 -0
  13. package/autoscaling/load_signal.js +135 -0
  14. package/autoscaling/memory_load_signal.d.ts +43 -0
  15. package/autoscaling/memory_load_signal.js +102 -0
  16. package/autoscaling/snapshotter.d.ts +29 -91
  17. package/autoscaling/snapshotter.js +65 -204
  18. package/autoscaling/system_status.d.ts +22 -37
  19. package/autoscaling/system_status.js +49 -87
  20. package/configuration.d.ts +88 -228
  21. package/configuration.js +162 -224
  22. package/cookie_utils.d.ts +4 -3
  23. package/cookie_utils.js +20 -13
  24. package/crawlers/context_pipeline.d.ts +70 -0
  25. package/crawlers/context_pipeline.js +122 -0
  26. package/crawlers/crawler_commons.d.ts +20 -30
  27. package/crawlers/crawler_commons.js +12 -21
  28. package/crawlers/crawler_utils.d.ts +2 -3
  29. package/crawlers/crawler_utils.js +1 -2
  30. package/crawlers/error_snapshotter.d.ts +3 -3
  31. package/crawlers/error_snapshotter.js +2 -3
  32. package/crawlers/error_tracker.d.ts +2 -2
  33. package/crawlers/error_tracker.js +0 -1
  34. package/crawlers/index.d.ts +1 -2
  35. package/crawlers/index.js +1 -2
  36. package/crawlers/internals/types.d.ts +7 -0
  37. package/crawlers/internals/types.js +1 -0
  38. package/crawlers/statistics.d.ts +28 -23
  39. package/crawlers/statistics.js +38 -34
  40. package/enqueue_links/enqueue_links.d.ts +44 -22
  41. package/enqueue_links/enqueue_links.js +51 -30
  42. package/enqueue_links/index.d.ts +0 -1
  43. package/enqueue_links/index.js +0 -1
  44. package/enqueue_links/shared.d.ts +25 -9
  45. package/enqueue_links/shared.js +69 -38
  46. package/errors.d.ts +53 -4
  47. package/errors.js +70 -5
  48. package/events/event_manager.d.ts +34 -8
  49. package/events/event_manager.js +8 -10
  50. package/events/index.d.ts +0 -1
  51. package/events/index.js +0 -1
  52. package/events/local_event_manager.d.ts +15 -5
  53. package/events/local_event_manager.js +37 -40
  54. package/index.d.ts +4 -3
  55. package/index.js +3 -2
  56. package/log.d.ts +82 -3
  57. package/log.js +102 -1
  58. package/memory-storage/consts.d.ts +4 -0
  59. package/memory-storage/consts.js +4 -0
  60. package/memory-storage/index.d.ts +1 -0
  61. package/memory-storage/index.js +1 -0
  62. package/memory-storage/memory-storage.d.ts +46 -0
  63. package/memory-storage/memory-storage.js +136 -0
  64. package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
  65. package/memory-storage/resource-clients/common/base-client.js +6 -0
  66. package/memory-storage/resource-clients/dataset.d.ts +40 -0
  67. package/memory-storage/resource-clients/dataset.js +113 -0
  68. package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
  69. package/memory-storage/resource-clients/key-value-store.js +203 -0
  70. package/memory-storage/resource-clients/request-queue.d.ts +96 -0
  71. package/memory-storage/resource-clients/request-queue.js +421 -0
  72. package/memory-storage/utils.d.ts +17 -0
  73. package/memory-storage/utils.js +42 -0
  74. package/package.json +12 -10
  75. package/proxy_configuration.d.ts +29 -152
  76. package/proxy_configuration.js +21 -173
  77. package/recoverable_state.d.ts +120 -0
  78. package/recoverable_state.js +141 -0
  79. package/request.d.ts +84 -13
  80. package/request.js +107 -28
  81. package/router.d.ts +118 -16
  82. package/router.js +124 -30
  83. package/serialization.d.ts +0 -1
  84. package/serialization.js +1 -2
  85. package/service_locator.d.ts +156 -0
  86. package/service_locator.js +238 -0
  87. package/session_pool/consts.d.ts +1 -2
  88. package/session_pool/consts.js +1 -2
  89. package/session_pool/errors.d.ts +0 -1
  90. package/session_pool/errors.js +0 -1
  91. package/session_pool/fingerprint.d.ts +9 -0
  92. package/session_pool/fingerprint.js +30 -0
  93. package/session_pool/index.d.ts +0 -2
  94. package/session_pool/index.js +0 -2
  95. package/session_pool/session.d.ts +37 -75
  96. package/session_pool/session.js +49 -102
  97. package/session_pool/session_pool.d.ts +85 -90
  98. package/session_pool/session_pool.js +131 -120
  99. package/storages/access_checking.d.ts +0 -1
  100. package/storages/access_checking.js +5 -2
  101. package/storages/dataset.d.ts +101 -51
  102. package/storages/dataset.js +168 -126
  103. package/storages/index.d.ts +8 -7
  104. package/storages/index.js +6 -7
  105. package/storages/key_value_store.d.ts +165 -36
  106. package/storages/key_value_store.js +269 -122
  107. package/storages/key_value_store_codec.d.ts +32 -0
  108. package/storages/key_value_store_codec.js +113 -0
  109. package/storages/request_dedup_cache.d.ts +23 -0
  110. package/storages/request_dedup_cache.js +48 -0
  111. package/storages/request_list.d.ts +53 -97
  112. package/storages/request_list.js +99 -75
  113. package/storages/request_loader.d.ts +96 -0
  114. package/storages/request_loader.js +1 -0
  115. package/storages/request_manager.d.ts +33 -0
  116. package/storages/request_manager.js +1 -0
  117. package/storages/request_manager_tandem.d.ts +106 -0
  118. package/storages/request_manager_tandem.js +197 -0
  119. package/storages/request_queue.d.ts +290 -47
  120. package/storages/request_queue.js +628 -215
  121. package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +28 -24
  122. package/storages/{sitemap_request_list.js → sitemap_request_loader.js} +49 -46
  123. package/storages/storage_instance_manager.d.ts +91 -0
  124. package/storages/storage_instance_manager.js +258 -0
  125. package/storages/storage_stats.d.ts +48 -0
  126. package/storages/storage_stats.js +29 -0
  127. package/storages/utils.d.ts +51 -6
  128. package/storages/utils.js +60 -9
  129. package/system-info/cpu-info.d.ts +67 -0
  130. package/system-info/cpu-info.js +216 -0
  131. package/system-info/memory-info.d.ts +31 -0
  132. package/system-info/memory-info.js +115 -0
  133. package/system-info/ps-tree.d.ts +17 -0
  134. package/system-info/ps-tree.js +144 -0
  135. package/system-info/runtime.d.ts +14 -0
  136. package/system-info/runtime.js +80 -0
  137. package/typedefs.d.ts +1 -2
  138. package/typedefs.js +0 -1
  139. package/validators.d.ts +8 -1
  140. package/validators.js +10 -3
  141. package/autoscaling/autoscaled_pool.d.ts.map +0 -1
  142. package/autoscaling/autoscaled_pool.js.map +0 -1
  143. package/autoscaling/index.d.ts.map +0 -1
  144. package/autoscaling/index.js.map +0 -1
  145. package/autoscaling/snapshotter.d.ts.map +0 -1
  146. package/autoscaling/snapshotter.js.map +0 -1
  147. package/autoscaling/system_status.d.ts.map +0 -1
  148. package/autoscaling/system_status.js.map +0 -1
  149. package/configuration.d.ts.map +0 -1
  150. package/configuration.js.map +0 -1
  151. package/cookie_utils.d.ts.map +0 -1
  152. package/cookie_utils.js.map +0 -1
  153. package/crawlers/crawler_commons.d.ts.map +0 -1
  154. package/crawlers/crawler_commons.js.map +0 -1
  155. package/crawlers/crawler_extension.d.ts +0 -12
  156. package/crawlers/crawler_extension.d.ts.map +0 -1
  157. package/crawlers/crawler_extension.js +0 -14
  158. package/crawlers/crawler_extension.js.map +0 -1
  159. package/crawlers/crawler_utils.d.ts.map +0 -1
  160. package/crawlers/crawler_utils.js.map +0 -1
  161. package/crawlers/error_snapshotter.d.ts.map +0 -1
  162. package/crawlers/error_snapshotter.js.map +0 -1
  163. package/crawlers/error_tracker.d.ts.map +0 -1
  164. package/crawlers/error_tracker.js.map +0 -1
  165. package/crawlers/index.d.ts.map +0 -1
  166. package/crawlers/index.js.map +0 -1
  167. package/crawlers/statistics.d.ts.map +0 -1
  168. package/crawlers/statistics.js.map +0 -1
  169. package/enqueue_links/enqueue_links.d.ts.map +0 -1
  170. package/enqueue_links/enqueue_links.js.map +0 -1
  171. package/enqueue_links/index.d.ts.map +0 -1
  172. package/enqueue_links/index.js.map +0 -1
  173. package/enqueue_links/shared.d.ts.map +0 -1
  174. package/enqueue_links/shared.js.map +0 -1
  175. package/errors.d.ts.map +0 -1
  176. package/errors.js.map +0 -1
  177. package/events/event_manager.d.ts.map +0 -1
  178. package/events/event_manager.js.map +0 -1
  179. package/events/index.d.ts.map +0 -1
  180. package/events/index.js.map +0 -1
  181. package/events/local_event_manager.d.ts.map +0 -1
  182. package/events/local_event_manager.js.map +0 -1
  183. package/http_clients/base-http-client.d.ts +0 -134
  184. package/http_clients/base-http-client.d.ts.map +0 -1
  185. package/http_clients/base-http-client.js +0 -33
  186. package/http_clients/base-http-client.js.map +0 -1
  187. package/http_clients/form-data-like.d.ts +0 -67
  188. package/http_clients/form-data-like.d.ts.map +0 -1
  189. package/http_clients/form-data-like.js +0 -5
  190. package/http_clients/form-data-like.js.map +0 -1
  191. package/http_clients/got-scraping-http-client.d.ts +0 -15
  192. package/http_clients/got-scraping-http-client.d.ts.map +0 -1
  193. package/http_clients/got-scraping-http-client.js +0 -69
  194. package/http_clients/got-scraping-http-client.js.map +0 -1
  195. package/http_clients/index.d.ts +0 -3
  196. package/http_clients/index.d.ts.map +0 -1
  197. package/http_clients/index.js +0 -3
  198. package/http_clients/index.js.map +0 -1
  199. package/index.d.ts.map +0 -1
  200. package/index.js.map +0 -1
  201. package/log.d.ts.map +0 -1
  202. package/log.js.map +0 -1
  203. package/proxy_configuration.d.ts.map +0 -1
  204. package/proxy_configuration.js.map +0 -1
  205. package/request.d.ts.map +0 -1
  206. package/request.js.map +0 -1
  207. package/router.d.ts.map +0 -1
  208. package/router.js.map +0 -1
  209. package/serialization.d.ts.map +0 -1
  210. package/serialization.js.map +0 -1
  211. package/session_pool/consts.d.ts.map +0 -1
  212. package/session_pool/consts.js.map +0 -1
  213. package/session_pool/errors.d.ts.map +0 -1
  214. package/session_pool/errors.js.map +0 -1
  215. package/session_pool/events.d.ts +0 -3
  216. package/session_pool/events.d.ts.map +0 -1
  217. package/session_pool/events.js +0 -3
  218. package/session_pool/events.js.map +0 -1
  219. package/session_pool/index.d.ts.map +0 -1
  220. package/session_pool/index.js.map +0 -1
  221. package/session_pool/session.d.ts.map +0 -1
  222. package/session_pool/session.js.map +0 -1
  223. package/session_pool/session_pool.d.ts.map +0 -1
  224. package/session_pool/session_pool.js.map +0 -1
  225. package/storages/access_checking.d.ts.map +0 -1
  226. package/storages/access_checking.js.map +0 -1
  227. package/storages/dataset.d.ts.map +0 -1
  228. package/storages/dataset.js.map +0 -1
  229. package/storages/index.d.ts.map +0 -1
  230. package/storages/index.js.map +0 -1
  231. package/storages/key_value_store.d.ts.map +0 -1
  232. package/storages/key_value_store.js.map +0 -1
  233. package/storages/request_list.d.ts.map +0 -1
  234. package/storages/request_list.js.map +0 -1
  235. package/storages/request_provider.d.ts +0 -307
  236. package/storages/request_provider.d.ts.map +0 -1
  237. package/storages/request_provider.js +0 -555
  238. package/storages/request_provider.js.map +0 -1
  239. package/storages/request_queue.d.ts.map +0 -1
  240. package/storages/request_queue.js.map +0 -1
  241. package/storages/request_queue_v2.d.ts +0 -87
  242. package/storages/request_queue_v2.d.ts.map +0 -1
  243. package/storages/request_queue_v2.js +0 -438
  244. package/storages/request_queue_v2.js.map +0 -1
  245. package/storages/sitemap_request_list.d.ts.map +0 -1
  246. package/storages/sitemap_request_list.js.map +0 -1
  247. package/storages/storage_manager.d.ts +0 -58
  248. package/storages/storage_manager.d.ts.map +0 -1
  249. package/storages/storage_manager.js +0 -105
  250. package/storages/storage_manager.js.map +0 -1
  251. package/storages/utils.d.ts.map +0 -1
  252. package/storages/utils.js.map +0 -1
  253. package/tsconfig.build.tsbuildinfo +0 -1
  254. package/typedefs.d.ts.map +0 -1
  255. package/typedefs.js.map +0 -1
  256. package/validators.d.ts.map +0 -1
  257. package/validators.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ import type { EventManager, EventTypeName } from '../events/event_manager.js';
2
+ import type { ClientInfo } from './system_status.js';
3
+ /**
4
+ * A snapshot of a resource's overload state at a point in time.
5
+ */
6
+ export interface LoadSnapshot {
7
+ createdAt: Date;
8
+ isOverloaded: boolean;
9
+ }
10
+ /**
11
+ * A signal that reports whether a particular resource is overloaded.
12
+ *
13
+ * `SystemStatus` aggregates multiple `LoadSignal` instances to determine
14
+ * overall system health. The built-in signals cover memory, CPU, event loop,
15
+ * and API client rate limits. You can implement this interface to add
16
+ * custom overload signals (e.g. navigation timeouts, proxy health).
17
+ */
18
+ export interface LoadSignal {
19
+ /** Human-readable name used in logging and `SystemInfo` keys. */
20
+ readonly name: string;
21
+ /**
22
+ * Maximum ratio of overloaded snapshots in a sample before the signal
23
+ * is considered overloaded. For example, `0.2` means the signal fires
24
+ * when more than 20% of the sample window is overloaded.
25
+ */
26
+ readonly overloadedRatio: number;
27
+ /** Start collecting snapshots. Called when the pool starts. */
28
+ start(): Promise<void>;
29
+ /** Stop collecting snapshots. Called when the pool shuts down. */
30
+ stop(): Promise<void>;
31
+ /**
32
+ * Return snapshots for a recent time window (used for "current" status).
33
+ * @param sampleDurationMillis How far back to look, in milliseconds.
34
+ */
35
+ getSample(sampleDurationMillis?: number): LoadSnapshot[];
36
+ }
37
+ /**
38
+ * A time-pruning, time-windowed store for `LoadSnapshot` values.
39
+ * Signals compose with this instead of inheriting from a base class.
40
+ */
41
+ export declare class SnapshotStore<T extends LoadSnapshot = LoadSnapshot> {
42
+ private snapshots;
43
+ private readonly historyMillis;
44
+ constructor(historyMillis?: number);
45
+ /**
46
+ * Add a snapshot and prune entries older than the history window.
47
+ */
48
+ push(snapshot: T, now?: Date): void;
49
+ /**
50
+ * Return all snapshots, or only those within the given time window.
51
+ */
52
+ getSample(sampleDurationMillis?: number): T[];
53
+ /**
54
+ * Direct access to the underlying array (for backward-compat getters).
55
+ */
56
+ getAll(): T[];
57
+ /**
58
+ * Create a `LoadSignal` that snapshots on a `betterSetInterval` tick.
59
+ *
60
+ * The `handler` receives the store (to read previous snapshots) and the
61
+ * interval callback (which it **must** call when done). It should call
62
+ * `store.push()` to record a snapshot.
63
+ */
64
+ static fromInterval<T extends LoadSnapshot>(options: {
65
+ name: string;
66
+ overloadedRatio: number;
67
+ intervalMillis: number;
68
+ snapshotHistoryMillis?: number;
69
+ handler: (store: SnapshotStore<T>, intervalCallback: () => unknown) => void;
70
+ }): Omit<LoadSignal, 'getSample'> & {
71
+ store: SnapshotStore<T>;
72
+ handle: (cb: () => unknown) => void;
73
+ getSample(sampleDurationMillis?: number): T[];
74
+ };
75
+ /**
76
+ * Create a `LoadSignal` that snapshots in response to an `EventManager` event.
77
+ *
78
+ * The `handler` receives the event payload and the store. It should call
79
+ * `store.push()` to record a snapshot.
80
+ */
81
+ static fromEvent<T extends LoadSnapshot, E>(options: {
82
+ name: string;
83
+ overloadedRatio: number;
84
+ events: EventManager;
85
+ event: EventTypeName;
86
+ snapshotHistoryMillis?: number;
87
+ handler: (store: SnapshotStore<T>, payload: E) => void;
88
+ }): Omit<LoadSignal, 'getSample'> & {
89
+ store: SnapshotStore<T>;
90
+ handle: (payload: E) => void;
91
+ getSample(sampleDurationMillis?: number): T[];
92
+ };
93
+ }
94
+ /**
95
+ * Evaluate whether a sample of `LoadSnapshot` values exceeds the given
96
+ * overloaded ratio, using a time-weighted average. This is the shared
97
+ * evaluation logic used by `SystemStatus` for all signal types.
98
+ */
99
+ export declare function evaluateLoadSignalSample(sample: LoadSnapshot[], overloadedRatio: number): ClientInfo;
@@ -0,0 +1,135 @@
1
+ import { weightedAvg } from '@crawlee/utils';
2
+ import { betterClearInterval, betterSetInterval } from '@apify/utilities';
3
+ /**
4
+ * A time-pruning, time-windowed store for `LoadSnapshot` values.
5
+ * Signals compose with this instead of inheriting from a base class.
6
+ */
7
+ export class SnapshotStore {
8
+ snapshots = [];
9
+ historyMillis;
10
+ constructor(historyMillis = 30_000) {
11
+ this.historyMillis = historyMillis;
12
+ }
13
+ /**
14
+ * Add a snapshot and prune entries older than the history window.
15
+ */
16
+ push(snapshot, now = snapshot.createdAt) {
17
+ // Inline pruning to avoid private-method transpilation issues
18
+ let oldCount = 0;
19
+ for (let i = 0; i < this.snapshots.length; i++) {
20
+ const { createdAt } = this.snapshots[i];
21
+ if (now.getTime() - new Date(createdAt).getTime() > this.historyMillis)
22
+ oldCount++;
23
+ else
24
+ break;
25
+ }
26
+ if (oldCount)
27
+ this.snapshots.splice(0, oldCount);
28
+ this.snapshots.push(snapshot);
29
+ }
30
+ /**
31
+ * Return all snapshots, or only those within the given time window.
32
+ */
33
+ getSample(sampleDurationMillis) {
34
+ if (!sampleDurationMillis)
35
+ return this.snapshots;
36
+ const sample = [];
37
+ let idx = this.snapshots.length;
38
+ if (!idx)
39
+ return sample;
40
+ const latestTime = this.snapshots[idx - 1].createdAt;
41
+ while (idx--) {
42
+ const snapshot = this.snapshots[idx];
43
+ if (+latestTime - +snapshot.createdAt <= sampleDurationMillis) {
44
+ sample.unshift(snapshot);
45
+ }
46
+ else {
47
+ break;
48
+ }
49
+ }
50
+ return sample;
51
+ }
52
+ /**
53
+ * Direct access to the underlying array (for backward-compat getters).
54
+ */
55
+ getAll() {
56
+ return this.snapshots;
57
+ }
58
+ /**
59
+ * Create a `LoadSignal` that snapshots on a `betterSetInterval` tick.
60
+ *
61
+ * The `handler` receives the store (to read previous snapshots) and the
62
+ * interval callback (which it **must** call when done). It should call
63
+ * `store.push()` to record a snapshot.
64
+ */
65
+ static fromInterval(options) {
66
+ const store = new SnapshotStore(options.snapshotHistoryMillis);
67
+ let interval = null;
68
+ const handle = (cb) => options.handler(store, cb);
69
+ return {
70
+ name: options.name,
71
+ overloadedRatio: options.overloadedRatio,
72
+ store,
73
+ handle,
74
+ getSample: (ms) => store.getSample(ms),
75
+ async start() {
76
+ interval = betterSetInterval(handle, options.intervalMillis);
77
+ },
78
+ async stop() {
79
+ betterClearInterval(interval);
80
+ },
81
+ };
82
+ }
83
+ /**
84
+ * Create a `LoadSignal` that snapshots in response to an `EventManager` event.
85
+ *
86
+ * The `handler` receives the event payload and the store. It should call
87
+ * `store.push()` to record a snapshot.
88
+ */
89
+ static fromEvent(options) {
90
+ const store = new SnapshotStore(options.snapshotHistoryMillis);
91
+ const handle = (payload) => options.handler(store, payload);
92
+ return {
93
+ name: options.name,
94
+ overloadedRatio: options.overloadedRatio,
95
+ store,
96
+ handle,
97
+ getSample: (ms) => store.getSample(ms),
98
+ async start() {
99
+ options.events.on(options.event, handle);
100
+ },
101
+ async stop() {
102
+ options.events.off(options.event, handle);
103
+ },
104
+ };
105
+ }
106
+ }
107
+ /**
108
+ * Evaluate whether a sample of `LoadSnapshot` values exceeds the given
109
+ * overloaded ratio, using a time-weighted average. This is the shared
110
+ * evaluation logic used by `SystemStatus` for all signal types.
111
+ */
112
+ export function evaluateLoadSignalSample(sample, overloadedRatio) {
113
+ if (sample.length === 0) {
114
+ return {
115
+ isOverloaded: false,
116
+ limitRatio: overloadedRatio,
117
+ actualRatio: 0,
118
+ };
119
+ }
120
+ const weights = [];
121
+ const values = [];
122
+ for (let i = 1; i < sample.length; i++) {
123
+ const previous = sample[i - 1];
124
+ const current = sample[i];
125
+ const weight = +current.createdAt - +previous.createdAt;
126
+ weights.push(weight || 1); // Prevent errors from 0ms long intervals (sync) between snapshots.
127
+ values.push(+current.isOverloaded);
128
+ }
129
+ const wAvg = sample.length === 1 ? +sample[0].isOverloaded : weightedAvg(values, weights);
130
+ return {
131
+ isOverloaded: wAvg > overloadedRatio,
132
+ limitRatio: overloadedRatio,
133
+ actualRatio: Math.round(wAvg * 1000) / 1000,
134
+ };
135
+ }
@@ -0,0 +1,43 @@
1
+ import type { Configuration } from '../configuration.js';
2
+ import type { CrawleeLogger } from '../log.js';
3
+ import type { LoadSignal, LoadSnapshot } from './load_signal.js';
4
+ import type { SystemInfo } from './system_status.js';
5
+ export interface MemorySnapshot extends LoadSnapshot {
6
+ usedBytes?: number;
7
+ }
8
+ export interface MemoryLoadSignalOptions {
9
+ maxUsedMemoryRatio?: number;
10
+ overloadedRatio?: number;
11
+ snapshotHistoryMillis?: number;
12
+ config: Configuration;
13
+ log?: CrawleeLogger;
14
+ }
15
+ /**
16
+ * Tracks memory usage via `SYSTEM_INFO` events and reports overload when
17
+ * the used-to-available memory ratio exceeds a threshold.
18
+ */
19
+ export declare class MemoryLoadSignal implements LoadSignal {
20
+ readonly name = "memInfo";
21
+ readonly overloadedRatio: number;
22
+ private readonly store;
23
+ private readonly config;
24
+ private readonly events;
25
+ private readonly log;
26
+ private readonly maxUsedMemoryRatio;
27
+ private maxMemoryRatio;
28
+ private maxMemoryBytes;
29
+ private lastLoggedCriticalMemoryOverloadAt;
30
+ constructor(options: MemoryLoadSignalOptions);
31
+ start(): Promise<void>;
32
+ stop(): Promise<void>;
33
+ getSample(sampleDurationMillis?: number): MemorySnapshot[];
34
+ /**
35
+ * Returns typed memory snapshots for backward compatibility with `Snapshotter`.
36
+ */
37
+ getMemorySnapshots(): MemorySnapshot[];
38
+ /** @internal */
39
+ _onSystemInfo(systemInfo: SystemInfo): void;
40
+ /** @internal */
41
+ _memoryOverloadWarning(systemInfo: SystemInfo, maxMemoryBytes?: number): void;
42
+ private _getTotalMemoryBytes;
43
+ }
@@ -0,0 +1,102 @@
1
+ import { serviceLocator } from '../service_locator.js';
2
+ import { getMemoryInfo } from '../system-info/memory-info.js';
3
+ import { isContainerized } from '../system-info/runtime.js';
4
+ import { SnapshotStore } from './load_signal.js';
5
+ const RESERVE_MEMORY_RATIO = 0.5;
6
+ const CRITICAL_OVERLOAD_RATE_LIMIT_MILLIS = 10_000;
7
+ /**
8
+ * Tracks memory usage via `SYSTEM_INFO` events and reports overload when
9
+ * the used-to-available memory ratio exceeds a threshold.
10
+ */
11
+ export class MemoryLoadSignal {
12
+ name = 'memInfo';
13
+ overloadedRatio;
14
+ store;
15
+ config;
16
+ events;
17
+ log;
18
+ maxUsedMemoryRatio;
19
+ maxMemoryRatio;
20
+ maxMemoryBytes;
21
+ lastLoggedCriticalMemoryOverloadAt = null;
22
+ constructor(options) {
23
+ this.store = new SnapshotStore(options.snapshotHistoryMillis);
24
+ this.config = options.config;
25
+ this.events = serviceLocator.getEventManager();
26
+ this.log = options.log ?? serviceLocator.getLogger().child({ prefix: 'MemoryLoadSignal' });
27
+ this.maxUsedMemoryRatio = options.maxUsedMemoryRatio ?? 0.9;
28
+ this.overloadedRatio = options.overloadedRatio ?? 0.2;
29
+ this._onSystemInfo = this._onSystemInfo.bind(this);
30
+ }
31
+ async start() {
32
+ const memoryMbytes = this.config.memoryMbytes ?? 0;
33
+ if (memoryMbytes > 0) {
34
+ this.maxMemoryBytes = memoryMbytes * 1024 * 1024;
35
+ }
36
+ else {
37
+ this.maxMemoryRatio = this.config.availableMemoryRatio;
38
+ if (!this.maxMemoryRatio) {
39
+ throw new Error('availableMemoryRatio is not set in configuration.');
40
+ }
41
+ else {
42
+ this.log.debug(`Setting max memory of this run to ${this.maxMemoryRatio * 100} % of available memory. ` +
43
+ 'Use the CRAWLEE_MEMORY_MBYTES or CRAWLEE_AVAILABLE_MEMORY_RATIO environment variable to override it.');
44
+ }
45
+ // Fallback memory measurement in case memTotalBytes is missing from SystemInfo.
46
+ this.maxMemoryBytes = await this._getTotalMemoryBytes();
47
+ }
48
+ this.events.on("systemInfo" /* EventType.SYSTEM_INFO */, this._onSystemInfo);
49
+ }
50
+ async stop() {
51
+ this.events.off("systemInfo" /* EventType.SYSTEM_INFO */, this._onSystemInfo);
52
+ }
53
+ getSample(sampleDurationMillis) {
54
+ return this.store.getSample(sampleDurationMillis);
55
+ }
56
+ /**
57
+ * Returns typed memory snapshots for backward compatibility with `Snapshotter`.
58
+ */
59
+ getMemorySnapshots() {
60
+ return this.store.getAll();
61
+ }
62
+ /** @internal */
63
+ _onSystemInfo(systemInfo) {
64
+ const createdAt = systemInfo.createdAt ? new Date(systemInfo.createdAt) : new Date();
65
+ const { memCurrentBytes, memTotalBytes } = systemInfo;
66
+ let maxMemoryBytes = this.maxMemoryBytes;
67
+ if (this.maxMemoryRatio !== undefined && this.maxMemoryRatio > 0) {
68
+ maxMemoryBytes = this.maxMemoryRatio * (memTotalBytes ?? this.maxMemoryBytes);
69
+ }
70
+ const snapshot = {
71
+ createdAt,
72
+ isOverloaded: memCurrentBytes / maxMemoryBytes > this.maxUsedMemoryRatio,
73
+ usedBytes: memCurrentBytes,
74
+ };
75
+ this.store.push(snapshot, createdAt);
76
+ this._memoryOverloadWarning(systemInfo, maxMemoryBytes);
77
+ }
78
+ /** @internal */
79
+ _memoryOverloadWarning(systemInfo, maxMemoryBytes) {
80
+ const effectiveMax = maxMemoryBytes ?? this.maxMemoryBytes;
81
+ const { memCurrentBytes } = systemInfo;
82
+ const createdAt = systemInfo.createdAt ? new Date(systemInfo.createdAt) : new Date();
83
+ if (this.lastLoggedCriticalMemoryOverloadAt &&
84
+ +createdAt < +this.lastLoggedCriticalMemoryOverloadAt + CRITICAL_OVERLOAD_RATE_LIMIT_MILLIS)
85
+ return;
86
+ const maxDesiredMemoryBytes = this.maxUsedMemoryRatio * effectiveMax;
87
+ const reserveMemory = effectiveMax * (1 - this.maxUsedMemoryRatio) * RESERVE_MEMORY_RATIO;
88
+ const criticalOverloadBytes = maxDesiredMemoryBytes + reserveMemory;
89
+ const isCriticalOverload = memCurrentBytes > criticalOverloadBytes;
90
+ if (isCriticalOverload) {
91
+ const usedPercentage = Math.round((memCurrentBytes / effectiveMax) * 100);
92
+ const toMb = (bytes) => Math.round(bytes / 1024 ** 2);
93
+ this.log.warning('Memory is critically overloaded. ' +
94
+ `Using ${toMb(memCurrentBytes)} MB of ${toMb(effectiveMax)} MB (${usedPercentage}%). Consider increasing available memory.`);
95
+ this.lastLoggedCriticalMemoryOverloadAt = createdAt;
96
+ }
97
+ }
98
+ async _getTotalMemoryBytes() {
99
+ const containerized = this.config.containerized ?? (await isContainerized());
100
+ return (await getMemoryInfo({ containerized, logger: serviceLocator.getLogger() })).totalBytes;
101
+ }
102
+ }
@@ -1,9 +1,11 @@
1
- import type { StorageClient } from '@crawlee/types';
2
- import type { Log } from '@apify/log';
3
- import type { BetterIntervalID } from '@apify/utilities';
4
- import { Configuration } from '../configuration.js';
5
- import type { EventManager } from '../events/event_manager.js';
6
- import type { SystemInfo } from './system_status.js';
1
+ import type { StorageBackend } from '@crawlee/types';
2
+ import type { Configuration } from '../configuration.js';
3
+ import type { CrawleeLogger } from '../log.js';
4
+ import type { ClientSnapshot } from './client_load_signal.js';
5
+ import type { CpuSnapshot } from './cpu_load_signal.js';
6
+ import type { EventLoopSnapshot } from './event_loop_load_signal.js';
7
+ import type { LoadSignal } from './load_signal.js';
8
+ import type { MemorySnapshot } from './memory_load_signal.js';
7
9
  export interface SnapshotterOptions {
8
10
  /**
9
11
  * Defines the interval of measuring the event loop response time.
@@ -31,46 +33,22 @@ export interface SnapshotterOptions {
31
33
  /**
32
34
  * Defines the maximum number of new rate limit errors within
33
35
  * the given interval.
34
- * @default 1
36
+ * @default 3
35
37
  */
36
38
  maxClientErrors?: number;
37
39
  /**
38
40
  * Sets the interval in seconds for which a history of resource snapshots
39
41
  * will be kept. Increasing this to very high numbers will affect performance.
40
- * @default 60
42
+ * @default 30
41
43
  */
42
44
  snapshotHistorySecs?: number;
43
45
  /** @internal */
44
- log?: Log;
46
+ log?: CrawleeLogger;
45
47
  /** @internal */
46
- client?: StorageClient;
48
+ client?: StorageBackend;
47
49
  /** @internal */
48
50
  config?: Configuration;
49
51
  }
50
- interface MemorySnapshot {
51
- createdAt: Date;
52
- isOverloaded: boolean;
53
- usedBytes?: number;
54
- }
55
- interface CpuSnapshot {
56
- createdAt: Date;
57
- isOverloaded: boolean;
58
- usedRatio: number;
59
- ticks?: {
60
- idle: number;
61
- total: number;
62
- };
63
- }
64
- interface EventLoopSnapshot {
65
- createdAt: Date;
66
- isOverloaded: boolean;
67
- exceededMillis: number;
68
- }
69
- interface ClientSnapshot {
70
- createdAt: Date;
71
- isOverloaded: boolean;
72
- rateLimitErrorCount: number;
73
- }
74
52
  /**
75
53
  * Creates snapshots of system resources at given intervals and marks the resource
76
54
  * as either overloaded or not during the last interval. Keeps a history of the snapshots.
@@ -94,27 +72,26 @@ interface ClientSnapshot {
94
72
  *
95
73
  * Client becomes overloaded when rate limit errors (429 - Too Many Requests),
96
74
  * typically received from the request queue, exceed the set limit within the set interval.
75
+ *
97
76
  * @category Scaling
98
77
  */
99
78
  export declare class Snapshotter {
100
- log: Log;
101
- client: StorageClient;
102
- config: Configuration;
103
- events: EventManager;
104
- eventLoopSnapshotIntervalMillis: number;
105
- clientSnapshotIntervalMillis: number;
106
- snapshotHistoryMillis: number;
107
- maxBlockedMillis: number;
108
- maxUsedMemoryRatio: number;
109
- maxClientErrors: number;
110
- maxMemoryBytes: number;
111
- cpuSnapshots: CpuSnapshot[];
112
- eventLoopSnapshots: EventLoopSnapshot[];
113
- memorySnapshots: MemorySnapshot[];
114
- clientSnapshots: ClientSnapshot[];
115
- eventLoopInterval: BetterIntervalID;
116
- clientInterval: BetterIntervalID;
117
- lastLoggedCriticalMemoryOverloadAt: Date | null;
79
+ readonly log: CrawleeLogger;
80
+ readonly client: StorageBackend;
81
+ readonly config: Configuration;
82
+ private readonly memorySignal;
83
+ private readonly eventLoopSignal;
84
+ private readonly cpuSignal;
85
+ private readonly clientSignal;
86
+ /**
87
+ * Returns the four built-in signals as an array, so `SystemStatus` can
88
+ * iterate them alongside any custom `LoadSignal` instances.
89
+ */
90
+ getLoadSignals(): LoadSignal[];
91
+ get cpuSnapshots(): CpuSnapshot[];
92
+ get eventLoopSnapshots(): EventLoopSnapshot[];
93
+ get memorySnapshots(): MemorySnapshot[];
94
+ get clientSnapshots(): ClientSnapshot[];
118
95
  /**
119
96
  * @param [options] All `Snapshotter` configuration options.
120
97
  */
@@ -147,43 +124,4 @@ export declare class Snapshotter {
147
124
  * by the sampleDurationMillis parameter. If omitted, it returns a full snapshot history.
148
125
  */
149
126
  getClientSample(sampleDurationMillis?: number): ClientSnapshot[];
150
- /**
151
- * Finds the latest snapshots by sampleDurationMillis in the provided array.
152
- */
153
- protected _getSample<T extends {
154
- createdAt: Date;
155
- }>(snapshots: T[], sampleDurationMillis?: number): T[];
156
- /**
157
- * Creates a snapshot of current memory usage
158
- * using the Apify platform `systemInfo` event.
159
- */
160
- protected _snapshotMemory(systemInfo: SystemInfo): void;
161
- /**
162
- * Checks for critical memory overload and logs it to the console.
163
- */
164
- protected _memoryOverloadWarning(systemInfo: SystemInfo): void;
165
- /**
166
- * Creates a snapshot of current event loop delay.
167
- */
168
- protected _snapshotEventLoop(intervalCallback: () => unknown): void;
169
- /**
170
- * Creates a snapshot of current CPU usage using the Apify platform `systemInfo` event.
171
- */
172
- protected _snapshotCpu(systemInfo: SystemInfo): void;
173
- /**
174
- * Creates a snapshot of current API state by checking for
175
- * rate limit errors. Only errors produced by a 2nd retry
176
- * of the API call are considered for snapshotting since
177
- * earlier errors may just be caused by a random spike in
178
- * number of requests and do not necessarily signify API
179
- * overloading.
180
- */
181
- protected _snapshotClient(intervalCallback: () => unknown): void;
182
- /**
183
- * Removes snapshots that are older than the snapshotHistorySecs option
184
- * from the array (destructively - in place).
185
- */
186
- protected _pruneSnapshots(snapshots: MemorySnapshot[] | CpuSnapshot[] | EventLoopSnapshot[] | ClientSnapshot[], now: Date): void;
187
127
  }
188
- export {};
189
- //# sourceMappingURL=snapshotter.d.ts.map