You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 97286df
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/guides/architecture_overview.mdx
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -351,12 +351,12 @@ The <ApiLink to="class/EventManager">`EventManager`</ApiLink> is responsible for
351
351
Crawlee provides several implementations of the event manager:
352
352
353
353
- <ApiLinkto="class/EventManager">`EventManager`</ApiLink> is the base class for event management in Crawlee.
354
-
- <ApiLinkto="class/LocalEventManager">`LocalEventManager`</ApiLink> extends the base event manager for local environments by automatically emitting `SYSTEM_INFO` events at regular intervals. This provides real-time system metrics including CPU usage and memory consumption, which are essential for internal components like the <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/AutoscaledPool">`AutoscaledPool`</ApiLink>.
354
+
- <ApiLinkto="class/LocalEventManager">`LocalEventManager`</ApiLink> extends the base event manager for local environments by automatically emitting `SYSTEM_INFO` events at regular intervals. This provides real-time system metrics including CPU usage and memory consumption, which are essential for internal components like the <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/ConcurrencySystem">`ConcurrencySystem`</ApiLink>.
355
355
-[`ApifyEventManager`](https://docs.apify.com/sdk/python/reference/class/ApifyEventManager) - Manages events on the [Apify platform](https://apify.com/) (cloud-based). It is implemented in the [Apify SDK](https://docs.apify.com/sdk/python/).
356
356
357
357
:::info
358
358
359
-
You can learn more about <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/AutoscaledPool">`AutoscaledPool`</ApiLink> and their configuration in the [Scaling crawlers guide](./scaling-crawlers).
359
+
You can learn more about <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/ConcurrencySystem">`ConcurrencySystem`</ApiLink> and their configuration in the [Scaling crawlers guide](./scaling-crawlers).
As we build our crawler, we may want to control how many tasks it performs at any given time. In other words, how many requests it makes to the web we are trying to scrape. Crawlee offers several options to fine-tune the number of parallel tasks, limit the number of requests per minute, and optimize scaling based on available system resources.
14
15
@@ -20,7 +21,7 @@ All of these options are available across all crawlers provided by Crawlee. In t
20
21
21
22
## Max tasks per minute
22
23
23
-
The `max_tasks_per_minute` setting in <ApiLinkto="class/ConcurrencySettings">`ConcurrencySettings`</ApiLink> controls how many total tasks the crawler can process per minute. It ensures that tasks are spread evenly throughout the minute, preventing a sudden burst at the `max_concurrency` limit followed by idle time. By default, this is set to `Infinity`, meaning the crawler can run at full speed, limited only by `max_concurrency`. Use this option if you want to throttle your crawler to avoid overwhelming the target website with continuous requests.
24
+
The `max_tasks_per_minute` setting in <ApiLinkto="class/ConcurrencySettings">`ConcurrencySettings`</ApiLink> controls how many total tasks the crawler can process per minute. The tasks started over the last 60 seconds are counted, so the crawler may spend the whole limit early in the minute, as fast as its concurrency allows. It then waits until the oldest of those starts ages out of the window. By default, this is set to `Infinity`, meaning the crawler can run at full speed, limited only by `max_concurrency`. Use this option if you want to throttle your crawler to avoid overwhelming the target website with continuous requests.
@@ -44,9 +45,15 @@ The `desired_concurrency` option in the <ApiLink to="class/ConcurrencySettings">
44
45
{MinAndMaxConcurrencyExample}
45
46
</RunnableCodeBlock>
46
47
47
-
## Autoscaled pool
48
+
## Concurrency system
48
49
49
-
The <ApiLinkto="class/AutoscaledPool">`AutoscaledPool`</ApiLink> manages a pool of asynchronous, resource-intensive tasks that run in parallel. It keeps `min_concurrency` tasks running even while the system is overloaded, and starts additional tasks only when there is enough free CPU and memory. To monitor system resources, it leverages the <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/SystemStatus">`SystemStatus`</ApiLink> classes. If any task raises an exception, the error is propagated, and the pool is stopped. Every crawler uses an <ApiLinkto="class/AutoscaledPool">`AutoscaledPool`</ApiLink> under the hood.
50
+
Every crawler runs its requests through an <ApiLinkto="class/AutoscaledPool">`AutoscaledPool`</ApiLink>, and the pool asks a <ApiLinkto="class/ConcurrencySystem">`ConcurrencySystem`</ApiLink> whether there is room for one more request. The system is what keeps `min_concurrency` requests running even while the machine is overloaded, starts further ones only when there is enough free CPU and memory, and scales the budget up and down as the load changes. To monitor system resources, it leverages the <ApiLinkto="class/Snapshotter">`Snapshotter`</ApiLink> and <ApiLinkto="class/SystemStatus">`SystemStatus`</ApiLink> classes. If any task raises an exception, the error is propagated and the pool is stopped.
51
+
52
+
The crawler builds its own system from the `ConcurrencySettings` described above. Build one yourself and pass it as `concurrency_system` to go beyond those settings, or to share a single budget between several crawlers that would otherwise each scale against the whole machine and oversubscribe it. The budget goes to whoever asks for it first, so a crawler that joins a saturated system late may have to wait. Browser crawlers default to a lower `desired_concurrency` than the rest, and a supplied system replaces that default too, so set it in the `ConcurrencySettings` you build the system from. Holding the instance also lets you retune `min_concurrency` and `max_concurrency` while the crawl runs. The lifecycle of such a system belongs to you, so keep it open until every crawler using it has finished.
Copy file name to clipboardExpand all lines: docs/guides/scrapy_migration.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -195,7 +195,7 @@ The default (unnamed) <ApiLink to="class/Dataset">`Dataset`</ApiLink> stays on d
195
195
196
196
## Concurrency and throttling
197
197
198
-
Both Scrapy and Crawlee have settings to influence the scraping throughput, but they differ in their approach. Crawlee reads <ApiLinkto="class/ConcurrencySettings">`ConcurrencySettings`</ApiLink> and scales concurrency automatically based on system resources, as described in the [Scaling crawlers guide](./scaling-crawlers). Use <ApiLinkto="class/ConcurrencySettings#__init__">`max_tasks_per_minute`</ApiLink> to cap the request rate. It's close to `DOWNLOAD_DELAY`, but it limits the whole pool rather than adding a fixed delay per domain.
198
+
Both Scrapy and Crawlee have settings to influence the scraping throughput, but they differ in their approach. Crawlee reads <ApiLinkto="class/ConcurrencySettings">`ConcurrencySettings`</ApiLink> and scales concurrency automatically based on system resources, as described in the [Scaling crawlers guide](./scaling-crawlers). Use <ApiLinkto="class/ConcurrencySettings#__init__">`max_tasks_per_minute`</ApiLink> to cap the request rate. It's close to `DOWNLOAD_DELAY`, but it limits the whole pool rather than adding a fixed delay per domain. Requests aren't spaced out either. They start as fast as the concurrency allows until the cap for the last 60 seconds is reached, and then wait for that window to move on.
The storage clients now write their JSON data with camelCase keys, the same as Crawlee JS. This covers the metadata, request and record metadata files of `FileSystemStorageClient`, the request and record metadata JSON stored by `RedisStorageClient`, and the request JSON stored by `SqlStorageClient`. For example, `item_count` in a dataset's `__metadata__.json` becomes `itemCount`. The storage metadata documents of `RedisStorageClient` keep their snake_case keys.
61
61
62
62
Data written by v1 still loads, so an existing storage directory, Redis instance or database keeps working. Any tooling that reads these files directly needs to handle the camelCase keys.
63
+
64
+
## Concurrency is managed by `ConcurrencySystem`
65
+
66
+
Load monitoring and concurrency scaling moved from `AutoscaledPool` to the new `ConcurrencySystem`. A crawler builds a default system from its `concurrency_settings` for each run, so a crawler configured through `concurrency_settings` works as before. To cap the combined concurrency of several crawlers, pass one shared `ConcurrencySystem` to all of them through the new `concurrency_system` option.
67
+
68
+
The autoscaling classes now live in the public `crawlee.autoscaling` package, which replaces the private `crawlee._autoscaling`. Import `AutoscaledPool`, `ConcurrencySystem`, `ConcurrencyConsumer`, `SystemInfo` and `LoadRatioInfo` from there. `Snapshotter` and `SystemStatus` stay internal.
69
+
70
+
`AutoscaledPool` now only runs the task loop. If you create a pool yourself, note that:
71
+
72
+
-`system_status` and `concurrency_settings` are replaced by `concurrency_system`, which has to be active when the pool runs, and `consumer`, which identifies the pool to the system.
73
+
-`run_task_function` receives the id the task is booked under.
74
+
-`current_concurrency` comes from the concurrency system, so a shared system may count the tasks of other pools too. The pool's own tasks are counted by the new `own_concurrency`.
75
+
76
+
For example:
77
+
78
+
```python
79
+
# v1
80
+
from crawlee._autoscaling import AutoscaledPool, Snapshotter, SystemStatus
81
+
82
+
asyncwith Snapshotter.from_config() as snapshotter:
asyncwith ConcurrencySystem(settings) as concurrency_system:
98
+
pool = AutoscaledPool(
99
+
concurrency_system=concurrency_system,
100
+
consumer=ConcurrencyConsumer(id='my-pool'),
101
+
run_task_function=run_task, # Now called with the task id.
102
+
is_task_ready_function=is_task_ready,
103
+
is_finished_function=is_finished,
104
+
)
105
+
await pool.run()
106
+
```
107
+
108
+
## `max_tasks_per_minute` counts the last minute
109
+
110
+
`ConcurrencySettings.max_tasks_per_minute` now caps the tasks started over the last 60 seconds, the same as Crawlee JS. In v1, the pool spaced task starts evenly, `60 / max_tasks_per_minute` seconds apart. In v2, tasks start as fast as the concurrency allows until the cap is reached. The next ones wait until the oldest starts age out of the window. The rate over a minute stays the same, but tasks start in bursts. For details, see [Max tasks per minute](../guides/scaling-crawlers#max-tasks-per-minute).
111
+
112
+
The value has to be a whole number of at least 1, or infinity, which is the default. A fractional value, such as `0.5` or `7.5`, now raises `ValueError`.
113
+
114
+
## Autoscaling logs moved to DEBUG
115
+
116
+
The periodic log of the autoscaling state and the `Waiting for remaining tasks to finish` message are now logged at DEBUG instead of INFO. The crawler's status message at INFO still reports the desired concurrency.
117
+
118
+
The state log also has a new format. Instead of raw ratios for every resource, it names only the overloaded ones, with the share of time each spent over its threshold and its limit:
119
+
120
+
```text
121
+
current concurrency 3, desired 5, overloaded: cpu 58% of the time (limit 40%)
122
+
```
123
+
124
+
To read the concurrency values in code, use `crawler.concurrency_system`.
0 commit comments