Repository navigation
Description
Feature Request
Problem / Opportunity
When archive.org is slow or down, Open Library slows down or goes down with it. web.py workers are synchronous, so a page that waits on archive.org holds a worker for the whole timeout, and enough of those take the site down (Oct 14, 2026; see #13956).
#13956 caps concurrent IA availability requests from web.py and falls back to Solr's ebook_access on the work and author pages. Many other pages still call archive.org while rendering, some with long timeouts or none at all. This issue collects them so we can reduce our reliance on IA and fail gracefully everywhere.
This gets better on its own as pages move to FastAPI: an async worker keeps serving other requests while one waits on archive.org. When choosing what to migrate next, we should prioritize the pages below that call IA.
Success: when archive.org is slow or down, every page still loads quickly. IA-dependent parts show as unknown or fall back to data we have, instead of blocking.
Proposal
web.py pages that call IA while rendering (not covered by #13956)
| Page | IA call | Timeout | Risk |
|---|---|---|---|
/search/inside (plugins/inside/code.py) |
Full-text search API (fulltext_search_async through async_bridge) |
30s | High. Each slow search holds a worker for up to 30s. |
Your own My Books page, /people/X/books (plugins/upstream/mybooks.py) |
get_loans_of_user (IA loan API) and get_loan_history_data (S3 loan API), not cached |
10s each | High. Every logged-in user visiting their own My Books page. |
/account/loans (plugins/upstream/account.py, templates/account/loans.html) |
Loans, loan history, the user's waiting list, plus get_waitinglist_size() once per book in the template |
10s each | Medium. Several calls in a row, and more for users with many loans. |
/account/validate (signup form check) |
account_validation.ia_username_exists: requests.get, no timeout |
none | Medium. A hung IA holds the worker until gunicorn's 300s limit. |
/account/create |
InternetArchiveAccount.xauth("create"): requests.post, no timeout |
none | Medium, same reason. |
Homepage carousels (core/carousels.py) |
IA advanced search (lending.get_available) |
10s | Low to medium. The homepage is cached for 5 minutes, but a failed IA call caches an empty list and immediately retries synchronously, so each homepage cache miss during an outage makes two slow calls. |
Loan status for logged-in users on search results, carousels and book pages (macros/LoanStatus.html, lending.get_lending_state) |
find_loans and the waiting-list query |
10s | Low. Cached for 5–10 minutes and refreshed in the background, so IA is only called synchronously on a cold cache. |
/books/ia:<id> (plugins/openlibrary/connection.py), /show-records (views/showmarc.py) |
IA metadata, MARC fetch | 3s | Low. Rare pages, short timeouts. |
Not a problem: covers only build URLs and never call IA, the search page's "Search Inside" band is lazy-loaded from a FastAPI partial, and FastAPI's borrow flow is fully async.
Beyond HTML pages
- FastAPI login blocks its whole worker.
async def logininopenlibrary/fastapi/account.pycallsaudit_accounts()directly, which makes a blockingrequestscall to IA (xauth/s3auth) with no timeout, on the event loop. While IA hangs, every request on that FastAPI worker stalls, not just the login. Fix: add a timeout and move the call off the event loop (e.g.run_in_threadpool, or an async httpx client). - Borrowing on web.py and the Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956 cap. web.py still has its own borrow route (
plugins/upstream/borrow.py). If production routes/books/.../borrowto web.py rather than FastAPI, the availability check inside the borrow goes through the cap, and when the cap is full it would see"error"and the borrow could fail. The routing lives in olsystem's haproxy config, so this needs checking there.
Suggested order
- Add timeouts to the two no-timeout calls, and stop the FastAPI login from blocking the event loop. Small and low-risk.
- Put
/search/insideand the My Books / loans calls behind the same limit as Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956, under their own metric names (fts,loans), or migrate those pages to FastAPI. - Stop the homepage carousels from caching and retrying an empty IA result.
- Longer term: put availability in Solr so pages don't need live IA calls at all (blocked on hardware for the reindex).
Related
- Keeping up Open Library during IA outage #6976 Keeping up Open Library during IA outage (2022): the original issue for this; this one updates it with today's call sites
- Book Availability in Solr #7450 Book Availability in Solr: the long-term fix, so pages don't need live availability calls
- Create replicas of key systems to enable automatic failover during downtime #8043 Create replicas of key systems to enable automatic failover during downtime
- [Reliability/Security] Many outbound requests calls have no timeout=, blocking workers indefinitely #12704 Many outbound requests calls have no
timeout=(closed, but thexauth/s3authand/account/validatecalls above still have none) - Internal Booklending_utils blocking OL on IA downtime #13023 Internal Booklending_utils blocking OL on IA downtime (closed)
- Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956 / Disable IA availability request from get_sorted_editions #13344: the concurrency limit and the hotfix it builds on
Breakdown
Implementation Details (for maintainers)
Related files
Refer to this map of common Endpoints:
openlibrary/core/ia_bulkhead.py: the concurrency limit from Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956openlibrary/core/lending.py:get_loans_of_user,get_loan_history_data,s3_loan_api_async,get_available_async,IA_Lending_APIopenlibrary/core/fulltext.py,openlibrary/plugins/inside/code.py: search insideopenlibrary/plugins/upstream/mybooks.py,openlibrary/plugins/upstream/account.py,openlibrary/templates/account/loans.htmlopenlibrary/accounts/model.py:InternetArchiveAccount.xauth,s3auth,audit_accountsopenlibrary/fastapi/account.py: FastAPI loginopenlibrary/core/carousels.py: homepage carousels
Requirements Checklist
Checklist of requirements that need to be satisfied in order for this issue to be closed:
- Every outbound IA call made during a web.py request has a timeout
- FastAPI login doesn't block the event loop
- Confirm whether production routes borrow to web.py or FastAPI
- Each high/medium-risk page above is capped, degrades gracefully, or has moved to FastAPI
- Homepage carousels don't retry IA synchronously after a failure
Stakeholders
Instructions for Contributors
- Before creating a new branch or pushing up changes to a PR, please first run these commands to ensure your repository is up to date, as the pre-commit bot may add commits to your PRs upstream.
Activity
openlibrary-bot commentedon Oct 16, 2026
Context (research findings)
openlibrary/core/lending.pyalready has 5/10-minute memoized wrappers sitting right next to the two "not cached" calls this issue flags:get_cached_loans_of_userandget_cached_user_waiting_loans.User.get_loan_for()incore/models.pyalready supports calling either the cached or raw version via ause_cacheflag:openlibrary/openlibrary/core/models.py
Lines 1108 to 1116 in 920c561
mybooks.pycalls the raw, uncachedget_loans_of_userdirectly:openlibrary/openlibrary/plugins/upstream/mybooks.py
Line 78 in 920c561
use_cache=True) removes a synchronous, uncached IA call on every logged-in visit without new infrastructure.ia_bulkhead.pyor equivalent onmaster). Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956 is itself still open, and its implementation is in an open PR: Cap concurrent IA availability requests from web.py, with a Solr fallback #13971 ("Cap concurrent IA availability requests from web.py, with a Solr fallback", opened by @RayBB the same day as this issue). Suggested order step 2 ("put/search/insideand the My Books / loans calls behind the same limit as Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956") is therefore dependent on Cap concurrent IA availability requests from web.py, with a Solr fallback #13971 landing first, not on existing infrastructure.get_sorted_editions", @cdrini) — the hotfix Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956 says it supersedes — is also still open/unmerged.InternetArchiveAccount.xauth()'srequests.post(L882) ands3auth()'srequests.get(L908) both have notimeout=argument, matching the issue's claim for/account/validateand/account/create.async def logincallsaudit_accounts()directly and synchronously on the event loop, with norun_in_threadpoolor async offload:openlibrary/openlibrary/fastapi/account.py
Lines 402 to 436 in 920c561
/show-records(show_marc) 3s-timeout item in this issue's table overlaps with MARC show-records timeouts #13874 ("MARC show-records timeouts", open,Priority: 1,Lead: @hornc), which is actively investigating live timeout failures on the exact same code path (openlibrary/views/showmarc.py). Worth linking so the two don't get fixed independently/inconsistently.Issue Assessment
Open questions
/account/loans'sget_waitinglist_size()really called once per book in the template with no batching? (Answer: Yes —openlibrary/templates/account/loans.htmlcallsbook.get_waitinglist_size()inline per row, twice in the template (lines 108 and 174, for the two loan tables), each a separate synchronous IA-backed lookup.)/books/.../borrowto web.py or FastAPI? This determines whether web.py's own borrow route (and the Cap concurrent Internet Archive availability requests globally so a slow archive.org can't take down Open Library #13956/Cap concurrent IA availability requests from web.py, with a Solr fallback #13971 availability cap) is actually reachable in production.olsystemis a private/internal repo, so this can't be confirmed fromopenlibraryalone — needs someone with infra access.🔔 Stakeholders
@cdrini — author of #13344 (the hotfix this issue's premise references) and owner of the #13956/#13971 concurrency-cap work this issue's Suggested-order step 2 depends on; also the listed search/frontend-performance lead relevant to the
/search/insideitem.Full triage checklist
Priority: 2andLead: @RayBBalready set; addedTheme: Book Availability,Theme: Search,Theme: My Books,Module: FastAPI,Module: Carousels,Affects: Serverto reflect the sub-areas coveredNote
This comment was automatically generated by Richy, Open Library's issue enrichment assistant, on behalf of @mekarpeles. This is NOT a sign-off. This issue needs lead review before work begins.
RsbhThakur commentedon Oct 16, 2026
@RayBB, I would like to work on this issue.
RayBB commentedon Oct 17, 2026
@RsbhThakur this one is still in the proposal phase with more to flesh out. If there's a particular part you think is easy and clear that we should do you can open a PR for it but ootherwise please take a simpler issue!
Ved-sketch commentedon Nov 9, 2026
Hi @RayBB,
I'd like to help with this issue. After reading #13970, #13956/#13971 and #14289, here's what I found:
ia_username_exists,xauth,s3auth) have no timeout.async def, which stalls the whole worker.get_loans_of_user, although a cached wrapper already exists.I'd like to start with timeouts on the account calls. Adding them raises a few edge cases I'd like your view on:
A timeout should help a lot, but it only shortens how long each worker is stuck, so the cap in #13971 is still needed for full protection.
Could you let me know which behavior you prefer, and whether anyone is already working on this?After that, I’d like to move on to the FastAPI login fix, then the My Books cache, the carousel caching, and /account/loans, if those are still free.
Thanks!