Skip to content

feat(crawlers)!: give each crawler after the first its own default request queue - #2344

Open
Mantisus wants to merge 3 commits into
apify:v2from
Mantisus:separate-df-rq
Open

Mantisus wants to merge 3 commits into
apify:v2from
Mantisus:separate-df-rq

Conversation

@Mantisus

Copy link
Copy Markdown
Collaborator

Description

Crawlers created without a request_manager no longer share the default request queue. The first crawler in the process still uses it, and every later one opens its own queue under the alias __default_{id}__, so crawlers don't share requests or their deduplication. The upgrade guide has a section for the change.

Issues

✍️ Drafted by Claude Code

@Mantisus Mantisus self-assigned this Oct 20, 2026
@github-actions github-actions Bot added the t-tooling Issues with this label are in the ownership of the tooling team. label Oct 20, 2026
@Mantisus
Mantisus requested review from Pijukatel and vdusek October 20, 2026 19:17

@Pijukatel Pijukatel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some questions.


A crawler without an `id` gets its creation index, such as `'0'`, and crawlers with an explicit `id` now count towards that index too. If you resume a v1 run with `purge_on_start=False` and mix both kinds of crawlers, a generated `id` can differ from the one v1 assigned, and the crawler won't find the state that `use_state` stored under the old one.

## Only the first crawler uses the default request queue

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be some warning about multiprocessing cases breaking some assumptions and thus not behaving the same way out of the box?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. Our documentation doesn't contain any recommendations regarding multiprocessing.

else:
self._id = id
self._id = str(BasicCrawler.__next_id) if id is None else id
self._default_rq_alias = None if BasicCrawler.__next_id == 0 else f'__default_{self._id}__'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self._default_rq_alias = None

Just double-checking since now is a good time for whatever breaking changes, are we sure that the default RQ should not have any alias?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep it. Many users run a single crawler on the default queue, and this way nothing changes for them. Also, on the Apify platform, the default queue is the run's default storage, so with an alias the first crawler's requests would go to a separate unnamed queue instead of the one the Console shows for the run.

Comment thread src/crawlee/crawlers/_basic/_basic_crawler.py Outdated
Comment thread src/crawlee/crawlers/_basic/_basic_crawler.py Outdated
Comment thread src/crawlee/crawlers/_basic/_basic_crawler.py
Comment thread tests/unit/crawlers/_basic/test_basic_crawler.py
@vdusek vdusek changed the title feat(crawlers)!: Stop sharing the default request queue between crawlers feat(crawlers)!: give each crawler after the first its own default request queue Oct 21, 2026
@vdusek vdusek linked an issue Oct 21, 2026 that may be closed by this pull request

@vdusek vdusek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great.

My only concern is the internal aliases we use for these RQs, specifically the first one.

Take this example:

crawler_1 = BasicCrawler()            # default RQ
crawler_2 = BasicCrawler()            # alias `__default_1__`
crawler_3 = BasicCrawler(id='blah')   # alias `__default_blah__`

With the FS storage backend, this ends up on disk as:

storage/request_queues/
├── default/
├── __default_1__/
└── __default_blah__/

Isn't this weird? The first queue breaks the pattern: it has no __ and no counter.

I'd find one consistent pattern clearer:

  • __default_{default_storage_counter}__ for crawlers without explicit id
  • __default_{crawler_id}__ for crawlers with explicit id

WDYT? Or is there any reason not do to it?

cc @janbuchar because of JS implementation

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-tooling Issues with this label are in the ownership of the tooling team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Give each crawler instance its own default request queue

4 participants