Skip to content

New: deep research, balance and auto-reload tools in the keyless MCP server. Install in one line

/search

Web search with the context already pruned

$1.00 per 1,000 searches, with page Markdown, highlights and pruned context in the same credit. 25 free a day with no key.

Recorded 2026-10-172,473 ms↓ 57% tokens
python asyncio timeout
  1. The asyncio Timeout Trap: Why wait_for() Doesn't Stop Tasks Instantly and How to Fix It

    I'll break down the common issues and offer sample code for alternatives in a friendly way! In Python's asyncio, timeouts are handled primarily using the asyncio.wait_for() utility. It wraps a coroutine or task and raises an asyncio.TimeoutError if the specified duration is exceeded. A frequent misunderstanding is that asyncio.wait_for() magically stops the task exactly at the timeout mark. The Reality import asyncio async def long_running_operation(): print("Task started...") This task doesn't check for cancellation or yield control It will run until the end, even after timeout await asyncio.sleep(5) print("Task finished (maybe too late!)") async def main_problem(): try: Timeout is 1 second await asyncio.wait_for(long_running_operation(), timeout=1.0) except asyncio.TimeoutError: print("Timeout occurred! ") The task might still be running for a while! print("Main continues...") asyncio.run(main_problem()) <hr> The best practice is to structure your long-running task so that it handles CancelledError and performs necessary cleanup. This ensures resources are released even if a timeout occurs. import asyncio async def gracefully_cancellable_task(): print("Graceful task: Starting work...") try: Simulate an operation await asyncio.sleep(3) print("Graceful task: Work finished successfully.") except asyncio.CancelledError: KEY STEP: Handle cancellation for cleanup print("Graceful task: Cancellation detected! Starting cleanup...") Imagine closing a connection or saving state here await asyncio.sleep(0.1) Cleanup time print("Graceful task: Cleanup finished.") raise Re-raise to let the waiter know it was cancelled async def main_graceful(): print("Main: Starting task with 1-second timeout...") try: await asyncio.wait_for(gracefully_cancellable_task(), timeout=1.0) except asyncio.TimeoutError: print("Main: Timeout occurred! Task should be cleaning up now.") Give the task a moment to finish cleanup before exiting (optional but safe) await asyncio.sleep(0.5) print("Main: Program exit.") asyncio.run(main_graceful())

  2. GitHub - aio-libs-abandoned/async-timeout: asyncio-compatible timeout class · GitHub

    asyncio-compatible timeout context manager. This library has effectively been upstreamed into Python 3.11+. Therefore this library is considered deprecated and no longer actively supported. Version 5.0+ provides dual-mode when executed on Python 3.11+: asyncio_timeout.Timeout is fully compatible with asyncio.Timeout and old versions of the library. Anyway, using upstream is highly recommended. asyncio_timeout exists only for the sake of backward compatibility, easy supporting both old and new Python by the same code, and easy misgration. If rescheduling API is not important and only async with timeout(...): ... functionality is required, a user could apply conditional import: if sys.version_info >= (3, 11): from asyncio import timeout, timeout_at else: from async_timeout import timeout, timeout_at The context manager is useful in cases when you want to apply timeout logic around block of code or in cases when asyncio.wait_for() is not suitable. Also it's much faster than asyncio.wait_for() because timeout doesn't create a new task. The timeout(delay) call returns a context manager that cancels a block on timeout expiring: from async_timeout import timeout async with timeout(1.5): await inner() async with timeout(1.5) as cm: recommended api cm.reschedule(cm.when() + 1) add another second on waiting compatible api cm.shift(1) add another second on waiting cm.update(loop.time() + 5) reschedule to now+5 seconds Rescheduling is forbidden if the timeout is expired or after exit from async with code block. Disable scheduled timeout: async with timeout(1.5) as cm: cm.reschedule(None) recommended api cm.reject() compatible api $ pip install async-timeout The library is Python 3 only! The module is written by Andrew Svetlov. It's Apache 2 licensed and freely available.

  3. The async with timeout: Best Practices for Robust Python Asynchronous I/O

    Here's a friendly breakdown of the asyncio.timeout() context manager, common pitfalls, and reliable alternatives. The asyncio.timeout() function provides a way to impose a time limit on an awaitable operation (like an asynchronous function, a task, or an I/O operation) within a specific block of code. It works as an async context manager When you enter the async with asyncio.timeout(delay): block, a timer starts. If the code inside the block finishes before the time limit (delay) expires, everything is normal. If the time limit is reached while the inner code is suspended at an await point, the execution is cancelled, and an asyncio.TimeoutError is raised at that await point. This example shows how to use it to limit the execution time of an operation. import asyncio async def long_running_operation(): print("Operation started...") await asyncio.sleep(5) Simulating a long I/O wait print("Operation finished successfully!") return "Data Acquired" async def main(): try: Set a timeout of 3 seconds async with asyncio.timeout(3) as cm: result = await long_running_operation() print(f"Result: {result}") except asyncio.TimeoutError: print(" Operation timed out!") You can access details about the remaining time via the context manager print(f"Time remaining at timeout: {cm.when()}") if __name__ == "__main__": asyncio.run(main()) Expected Output (since 3 < 5): Operation started... Operation timed out! import time async def blocking_code_issue(): async with asyncio.timeout(1): This is synchronous and blocks the entire event loop for 5 seconds. The timeout cannot interrupt it. print("Starting blocking work...") time.sleep(5) print("Finished blocking work (timeout was ineffective)") The TimeoutError will only raise after this finishes, or at the next await, which is often too late or confusing. To handle long-running, CPU-bound (blocking) operations, you should run them in a separate thread or process pool using asyncio.to_thread() (Python 3.9+) or loop.run_in_executor().

  4. Python asyncio.wait_for(): Cancel a Task with a Timeout

    Summary: in this tutorial, you’ll learn how to use the asyncio.wait_for() function to wait for a coroutine to complete with a timeout. Introduction to the Python asyncio.wait_for() function # In the previous tutorial, you learned how to cancel a task that is in progress by using the cancel() method of the Task object. To wait for a task to complete with a timeout, you can use the asyncio.wait_for() function. The asyncio.wait_for() function waits for a single task to be completed with a timeout. When a timeout occurs, the asyncio.wait_for() function cancels the task and raises the TimeoutError exception. Otherwise, it returns the result of the task. For example: import asyncio from asyncio.exceptions import TimeoutError async def call_api(message, result=1000, delay=3): print(message) await asyncio.sleep(delay) return result async def main(): task = asyncio.create_task( call_api('Calling API...', result=2000, delay=5) ) MAX_TIMEOUT = 3 try: await asyncio.wait_for(task, timeout=MAX_TIMEOUT) except TimeoutError: print('The task was cancelled due to a timeout') asyncio.run(main()) Copy Output: Calling API... The task was cancelled due to a timeoutCopy How it works First, define a call_api() coroutine that takes 3 seconds to complete by default: async def call_api(message, result=1000, delay=3): print(message) await asyncio.sleep(delay) return resultCopy Second, create a task that wraps the call_api coroutine and takes 5 seconds to complete: task = asyncio.create_task( call_api('Calling API...', result=2000, delay=5) )Copy Third, use the asyncio.wait_for() function to wait for the task to complete with a timeout of 3 seconds. Since the task takes 5 seconds to complete, a timeout will occur and a TimeoutError will be raised:

  5. High-level API Index — Python 3.15.0 documentation

    This page lists all high-level async/await enabled asyncio APIs. Tasks Utilities to run asyncio programs, create Tasks, and await on multiple things with timeouts. | run() | Create event loop, run a coroutine, close the loop. | | Runner | A context manager that simplifies multiple async function calls. | | Task | Task object. | | TaskGroup | A context manager that holds a group of tasks. Provides a convenient and reliable way to wait for all tasks in the group to finish. | | create_task() | Start an asyncio Task, then returns it. | | current_task() | Return the current Task.

Works with

A drop-in base URL for Exa and Tavily SDKs, and a keyless MCP server for coding agents.

  • Claude CodeMCP, one line
  • CursorMCP server
  • WindsurfMCP server
  • exa_pychange base_url
  • tavily-pythonchange api_base_url
  • Any MCP clientstdio, keyless

Outputs purpose-built for your agents

Pick what each result carries. Everything below comes from one recorded search and costs one credit.

The asyncio Timeout Trap: Why wait_for() Doesn't Stop Tasks Instantly and How to Fix Itrunebook.dev

I'll break down the common issues and offer sample code for alternatives in a friendly way! In Python's asyncio, timeouts are handled primarily using the asyncio.wait_for() utility. It wraps a coroutine or task and raises an asyncio.TimeoutError if the specified duration is exceeded. A frequent misunderstanding is that asyncio.wait_for() magically stops the task exactly at the timeout mark. The Reality When asyncio.wait_for() raises TimeoutError, the underlying task is cancelled, but it might not stop execution immediately. The task needs to notice the cancellation (by checking task.cancelled() or catching asyncio.CancelledError) and clean up gracefully. If the task is stuck in a synchronous I/O call or a heavy CPU loop, it won't notice the cancellation until it returns to the event loop. import asyncio async def long_running_operation(): print("Task started...") This task doesn't check

Results

Ranked URLs with title, published date and score, plus the full page text when you ask for it.

  • The asyncio Timeout Trap: Why wait_for() Doesn't Stop Tasks Instantly and How to Fix Itrunebook.dev

    I'll break down the common issues and offer sample code for alternatives in a friendly way! In Python's asyncio, timeouts are handled primarily using the asyncio.wait_for() utility. It wraps a coroutine or task and raises an asyncio.TimeoutError if the specified duration is exceeded. A frequent misunderstanding is that asyncio.wait_for() magically stops the task exactly at the timeout mark. The Reality

  • GitHub - aio-libs-abandoned/async-timeout: asyncio-compatible timeout class · GitHubgithub.com

    asyncio-compatible timeout context manager. This library has effectively been upstreamed into Python 3.11+. Therefore this library is considered deprecated and no longer actively supported. Version 5.0+ provides dual-mode when executed on Python 3.11+: asyncio_timeout.Timeout is fully compatible with asyncio.Timeout and old versions of the library. Anyway, using upstream is highly recommended. asyncio_timeout exists only for the sake of backward compatibility, easy supporting both old and new Python by the same code, and easy misgration. If rescheduling API is not important and only async with timeout(...): ... functionality is required, a user could apply conditional import:

  • The async with timeout: Best Practices for Robust Python Asynchronous I/Orunebook.dev

    Here's a friendly breakdown of the asyncio.timeout() context manager, common pitfalls, and reliable alternatives. The asyncio.timeout() function provides a way to impose a time limit on an awaitable operation (like an asynchronous function, a task, or an I/O operation) within a specific block of code. It works as an async context manager When you enter the async with asyncio.timeout(delay): block, a timer starts. If the code inside the block finishes before the time limit (delay) expires, everything is normal.

  • Python asyncio.wait_for(): Cancel a Task with a Timeoutpythontutorial.net

    import asyncio from asyncio.exceptions import TimeoutError async def call_api(message, result=1000, delay=3): print(message) await asyncio.sleep(delay) return result async def main(): task = asyncio.create_task( call_api('Calling API...', result=2000, delay=5) ) MAX_TIMEOUT = 3 try: await asyncio.wait_for(task, timeout=MAX_TIMEOUT) except TimeoutError: print('The task was cancelled due to a timeout') asyncio.run(main()) Copy Output: Calling API... The task was cancelled due to a timeoutCopy How it works First, define a call_api() coroutine that takes 3 seconds to complete by default:

Highlights

The passages that match the query, ranked and scored, ready to quote.

Included in the credit
prunedContext5,322 → 2,305 tokens

asyncio-compatible timeout context manager. This library has effectively been upstreamed into Python 3.11+. Therefore this library is considered deprecated and no longer actively supported. Version 5.0+ provides dual-mode when executed on Python 3.11+: asyncio_timeout.Timeout is fully compatible with asyncio.Timeout and old versions of the library. Anyway, using upstream is highly recommended. asyncio_timeout exists only for the sake of backward compatibility, easy supporting both old and new Python by the same code, and easy misgration. If rescheduling API is not important and only async with timeout(...): ... functionality is required, a user could apply conditional import: if sys.version_info >= (3, 11): from asyncio import timeout, timeout_at else: from async_timeout import timeout, timeout_at The context manager is useful in cases when you want to apply timeout logic around block of code or in cases when asyncio.wait_for() is not suitable. Also it's much faster than asyncio.wait_for() because timeout doesn't create a new task. The timeout(delay) call returns a context manager that cancels a block on timeout expiring: from async_timeout import timeout async with timeout(1.5): await inner() async with timeout(1.5) as cm: recommended api cm.reschedule(cm.when() + 1) add another second on waiting compatible api cm.shift(1) add another second on waiting cm.update(loop.time() + 5) reschedule to now+5 seconds Rescheduling is forbidden if the timeout is expired or after exit from async with code block. Disable scheduled timeout: async with timeout(1.5) as cm: cm.reschedule(None) recommended api cm.reject() compatible api $ pip install async-timeout The library is Python 3 only! The module is written by Andrew Svetlov. It's Apache 2 licensed and freely available.

github.com

Pruned context

A cross-encoder keeps only what answers the query: 57% fewer tokens on this search.

Saves LLM tokens
runebook.dev
# The asyncio Timeout Trap: Why wait\_for() Doesn't Stop Tasks Instantly and How to Fix It

I'll break down the common issues and offer sample code for alternatives in a friendly way!

In Python's `asyncio`, timeouts are handled primarily using the `asyncio.wait_for()` utility. It wraps a coroutine or task and raises an `asyncio.TimeoutError` if the specified duration is exceeded.

A frequent misunderstanding is that `asyncio.wait_for()` magically stops the task exactly at the timeout mark.

The Reality

When `asyncio.wait_for()` raises `TimeoutError`, the underlying task is cancelled, but it might not stop execution immediately. The task needs to notice the cancellation (by checking `task.cancelled()` or catching `asyncio.CancelledError`) and clean up gracefully. If the task is stuck in a synchronous I/O call or a heavy CPU loop, it won't notice the cancellation until it returns to the event loop.

```python
import asyncio

async def long_running_operation():
    print("Task started...")
    # This task *doesn't* check for cancellation or yield control
    # It will run until the en

Markdown

Clean page Markdown with headings, tables and code blocks kept, not raw HTML.

Included in the credit

Priced per search, not per page

List price per 1,000 searches, alone and with page Markdown for 10 results. We have not measured competitors' quality or latency, so we only compare prices.

List price in US dollars per 1,000 searches, as of 2026-10-16
GroupContextFetchExaTavilyFirecrawlSerper
Search$1.00$7.00$8.00$1.20$1.00
Search + Markdown of 10 pages$1.00$17.00not available$7.19not available

Public list prices as of 2026-10-16. ContextFetch: Instant pack; Markdown included in the search credit. Exa: Auto/Fast search, contents billed per page. Tavily: Basic search, pay-as-you-go; raw_content price not in our sources. Firecrawl: Scale plan billed yearly, its lowest per-credit tier. Serper: Starter pack; returns SERP JSON, no page Markdown. Sources: Exa, Tavily, Firecrawl, Serper. n/a means not sold or not in those sources.

Quickstart

Keep your SDK, change one line

Point exa_py or exa-js at our base URL, or call the endpoint directly. Agents can use the MCP server instead.

  • Exa request and response shapes, camelCase or snake_case
  • Up to 25 results per search, domain and date filters
  • X-Credits-Remaining on every billable response

Endpoint reference

# pip install exa-pyfrom exa_py import Exa exa = Exa(api_key="YOUR_API_KEY", base_url="https://api.contextfetch.dev") res = exa.search(    "vector database benchmarks 2026",    num_results=5,    contents={"text": True, "highlights": True},)for r in res.results:    print(r.url, r.highlights)

Pricing

Search API for your agents

$1.00/ 1k searches

1 credit per search, up to 25 results. Down to $0.75 per 1k on the Scale pack. One-time payment. Credits never expire. Full Markdown and pruning included.

Questions

What does one search include?

Up to 25 results for 1 credit. Ask for contents (text, highlights, pruned_context) and each result also carries its page Markdown, the best-matching passages and a query-pruned context, in the same credit. Without contents, results carry no page text.

Is it compatible with Exa's SDKs?

Yes. POST /v1/search keeps Exa's request and response shapes, so exa_py and exa-js work after setting the base URL to https://api.contextfetch.dev. Any Exa search type is accepted; all run the same pipeline. Exa's answer, research, Websets and summary features are not available.

Can I filter by domain or date?

Yes: includeDomains, excludeDomains (up to 100 entries each) and startPublishedDate, in camelCase or snake_case.

How does the keyless tier work?

Send no Authorization header and you get 25 requests per IP per UTC day. Every billable response carries X-Credits-Remaining. When the allowance runs out the API answers HTTP 402 with a one-click payment link your agent can show its human.

What is the extra contextfetch field in the response?

Per-request facts SDKs ignore: whether the query cache answered, server timings per stage, and raw versus pruned token counts. The recorded example on this page reports them.

Give your agent the web

Start with 25 free searches a day. No key, no signup.