Skip to content

fix(duckduckgo): rate limit errors, and add new search engines option - #3829

Open
nikkoyuthinkcol wants to merge 7 commits into
langgenius:mainfrom
nikkoyuthinkcol:fix/duckduckgo-rate-limit
Open

fix(duckduckgo): rate limit errors, and add new search engines option#3829
nikkoyuthinkcol wants to merge 7 commits into
langgenius:mainfrom
nikkoyuthinkcol:fix/duckduckgo-rate-limit

Conversation

@nikkoyuthinkcol

@nikkoyuthinkcol nikkoyuthinkcol commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #3803. Search now works, but if you search too many times, it will have rate limit error. The error message is not obvious though, with error type: DDGSException, error details: No results found.

The solution is the do a failover, and exponential retry if that happens, this will be handy if users are using duckduckgo in parallel nodes.

Updated README.md as well.

Release Notes

Search no longer fails outright when your server is rate-limited by the upstream engines.

  • Searches are throttled and retried with exponential backoff, so workflows that run many search nodes in parallel or in loops no longer burst the engines and get blocked.
  • New Search engines option on Search and Image Search: pin a comma-separated list such as duckduckgo,brave,yahoo if some engines block your host. Leave empty to rotate through
    all of them.
  • The error raised when every engine blocks now explains the cause and how to work around it.

Change Type

  • Documentation / non-plugin change
  • Non-LLM plugin (tools, extensions, datasource, etc.)
  • LLM plugin

Screenshots / Videos

Before After
image image

Version

  • Bumped top-level version in manifest.yaml (not the one under meta) — 0.0.11 → 0.0.12
  • dify_plugin>=0.9.0

Testing

  • Local deployment — Dify version: 1.17.0
  • SaaS (cloud.dify.ai)

…e limits

Workflows that loop over several search nodes fire dozens of scrapes from
one host within a minute. ddgs then gets non-200 or captcha pages from
every engine and surfaces it as "No results found.", which aborts the run.

- Wrap DDGS calls in search_with_retry: 3 attempts with a fresh DDGS()
  each time (new fingerprint, reshuffled engines), exponential backoff
  2s/4s plus jitter, and a process-wide 2s throttle so parallel nodes
  queue instead of bursting.
- Raise the ddgs timeout from 5s to 10s so slower engines are not dropped
  before they answer, leaving only the ones most likely to be blocked.
- Add an optional `backend` parameter to text and image search so users
  can pin engines that still answer from their host.
- Re-raise with a message that says the host was likely blocked and how
  to work around it instead of the misleading upstream text.
- Document rate limiting and mitigations in the README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5g7Ac5MwrDtHJFAGcnyhi

@Mairuis Mairuis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The reviewed diff adds a shared retry/throttling helper for text and image searches without new regression tests. I have not reproduced a defect in the helper.

Suggested coverage: transient failure then success, attempt exhaustion, backend/proxy forwarding, and search-slot spacing across concurrent calls, using a mocked DDGS client and clock. These are testing suggestions rather than confirmed bugs or a separate repository policy.

For the empty-result message, keep the cause qualified: the helper cannot itself distinguish a genuinely empty result from an upstream block.

nikkoyuthinkcol and others added 2 commits September 8, 2026 19:15
Add regression tests for the shared ddgs retry helper, mocking the DDGS
client, the clock and the jitter source so no test touches the network:
transient failure then success, attempt exhaustion with exact backoff
delays, both final-error message branches, proxy/backend forwarding, and
search-slot spacing for parallel and looped callers.

Also qualify the message raised when every attempt returns "No results
found.". ddgs collapses an upstream block and a genuinely empty result
set into the same exception and discards the status code, so the helper
cannot distinguish them; the message now says a block is the likely
cause rather than asserting it, and keeps the workarounds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GMMc1xxBx6EwADxtHQfhyA
@nikkoyuthinkcol

Copy link
Copy Markdown
Contributor Author

Hi @Mairuis , I've created some tests, mind to review again? Thanks.

nikkoyuthinkcol and others added 3 commits September 11, 2026 14:13
Main independently bumped duckduckgo to 0.0.12 for an icon/dependency
refresh, colliding with this branch's own bump. Bump once more so the
rate-limit fix stays a distinct, installable version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HTVkHb8tWqz3qoaP6aVqV7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants