perf(bitbucket): offload blocking HTTP from async handlers - #2873
Conversation
PR Summary by QodoOffload blocking Bitbucket HTTP calls from async handlers
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo
1. global_settings bypasses get_settings()
|
IsmaelMartinez
left a comment
There was a problem hiding this comment.
Thanks, and the offload does what it says: a one-second blocking call lets a 10ms ticker through 92 times on this branch and zero times on main, with the JWT check still ahead of it so nothing is spawned before auth.
One thing to fix before merge. The new file shares a basename with tests/e2e_tests/test_bitbucket_app.py, and with no __init__.py under tests/ pytest imports both as one module, so a bare pytest dies with import file mismatch before running anything. CI is unaffected because every workflow passes a scoped path. Renaming to test_bitbucket_app_offload.py clears it.
Qodo's global_settings finding I would leave. A repo .pr_agent.toml can override that key through get_settings(), and a repo should not be able to raise a host timeout. Worth knowing its suggested fix routes through get_settings(use_context=False), whose argument is ignored in the function body, so it would reopen the hole rather than close it.
One test gap inline.
Move the OAuth token exchange and pull-request commit lookup to worker threads so slow Bitbucket requests do not block the FastAPI event loop. Bound both requests with a host-controlled timeout to prevent stalled endpoints from exhausting the shared executor. Add focused coverage for request delegation, timeout propagation, and graceful push validation.
b276e22 to
c904271
Compare
|
Code review by qodo was updated up to the latest commit c904271 |
|
@IsmaelMartinez LGTM, let me know if you have any more feedback on this one 🙏 |
IsmaelMartinez
left a comment
There was a problem hiding this comment.
Thanks again, approving and merging!
Problem
Two Bitbucket App code paths are declared
asyncbut perform synchronousrequestscalls directly on the event-loop thread:get_bearer_token()callsrequests.request()while exchanging the JWT for an OAuth access token._validate_time_from_last_commit_to_pr_update()callsrequests.get()while fetching the latest commits for push validation.When Bitbucket is slow, these calls block the FastAPI event loop for the duration of the network request and can delay unrelated webhook work handled by the same worker. Moving an unbounded request to the shared executor would also allow a stalled endpoint to occupy a worker thread indefinitely.
Changes
asyncio.to_thread()while preserving method, URL, headers, payload, response handling, and exception behavior.bitbucket_app.request_timeout, defaulting to 30 seconds and requiring a positive finite host value..pr_agent.tomlcannot extend shared executor occupancy.This intentionally does not introduce a new HTTP client/session, change retry policy, or modify other Bitbucket provider requests.
Validation
PYTHONPATH=. pytest tests/unittest/test_bitbucket_app.py tests/unittest/test_bitbucket_fork_safe_secret_provider.py tests/unittest/test_bitbucket_provider.py -q— 54 passedgit diff --checkpassed.