Skip to content

fix: add retry on polymarket's _get_market so a transient server error does not break the job#226

Merged
houtanb merged 1 commit into
forecastingresearch:mainfrom
nikbpetrov:polymarket-get-market-backoff
Jul 9, 2026
Merged

fix: add retry on polymarket's _get_market so a transient server error does not break the job#226
houtanb merged 1 commit into
forecastingresearch:mainfrom
nikbpetrov:polymarket-get-market-backoff

Conversation

@nikbpetrov

@nikbpetrov nikbpetrov commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Improved market lookup reliability by retrying temporary request failures with exponential backoff.
    • Reduced failed lookups from brief API/network interruptions.
  • Tests

    • Updated automated coverage to confirm lookups retry after an initial HTTP error and succeed on a later attempt.

@nikbpetrov nikbpetrov requested a review from houtanb June 18, 2026 09:53
@nikbpetrov nikbpetrov force-pushed the polymarket-get-market-backoff branch from 19b6d37 to 88291b3 Compare June 30, 2026 11:46
@houtanb

houtanb commented Jul 8, 2026

Copy link
Copy Markdown
Member

@CodeRabbit full review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 603df5e3-b383-4fa7-a6f1-5b34a58587fa

📥 Commits

Reviewing files that changed from the base of the PR and between 499a593 and 60343bb.

📒 Files selected for processing (2)
  • src/sources/polymarket.py
  • src/tests/test_polymarket.py

📝 Walkthrough

Walkthrough

Adds exponential backoff retry handling to PolymarketSource._get_market for transient requests.exceptions.RequestException errors, capped at 20 seconds. The test now checks retry-then-success behavior and the number of HTTP calls.

Changes

Backoff Retry for Market Fetch

Layer / File(s) Summary
Retry decorator and test coverage
src/sources/polymarket.py, src/tests/test_polymarket.py
_get_market now retries requests.exceptions.RequestException with exponential backoff, max_time=20, and data_utils.print_error_info_handler; the test now simulates a first failing request and a second successful request, asserting the returned market and two requests.get calls.

Estimated code review effort: 1 (Trivial) | ~5 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding retry logic to Polymarket's _get_market to handle transient failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/sources/polymarket.py (1)

294-322: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a timeout to the Polymarket API calls here

backoff.on_exception only retries raised RequestExceptions; without timeout, a stalled requests.get can block forever and never reach the retry path. Apply the same timeout to the other Polymarket requests.get calls in this module too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/sources/polymarket.py` around lines 294 - 322, The Polymarket API calls
in `_get_market` can hang indefinitely because `requests.get` has no timeout, so
the backoff retry never triggers on a stalled request. Add a timeout to the
`requests.get` calls in `_get_market` and apply the same timeout pattern to the
other Polymarket request methods in this module so all network calls fail fast
and can be retried by `backoff.on_exception`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/sources/polymarket.py`:
- Around line 294-322: The Polymarket API calls in `_get_market` can hang
indefinitely because `requests.get` has no timeout, so the backoff retry never
triggers on a stalled request. Add a timeout to the `requests.get` calls in
`_get_market` and apply the same timeout pattern to the other Polymarket request
methods in this module so all network calls fail fast and can be retried by
`backoff.on_exception`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aa061c8d-5be2-49ae-8bdc-d2ab5749def4

📥 Commits

Reviewing files that changed from the base of the PR and between 86a399d and 88291b3.

📒 Files selected for processing (2)
  • src/sources/polymarket.py
  • src/tests/test_polymarket.py

@houtanb houtanb force-pushed the polymarket-get-market-backoff branch from 88291b3 to 499a593 Compare July 8, 2026 17:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tests/test_polymarket.py`:
- Around line 567-568: The retry test is patching the wrong sleep target, so the
backoff pause still occurs during retries. Update the test around the polymarket
request retry path to patch backoff’s actual sleep call via
backoff._sync.time.sleep (or patch time.sleep globally) instead of
sources.polymarket.time.sleep, keeping the test fast while preserving the
existing requests.get mock and retry assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 936abf01-4449-4dc2-8803-7b5afd71a7b3

📥 Commits

Reviewing files that changed from the base of the PR and between 88291b3 and 499a593.

📒 Files selected for processing (2)
  • src/sources/polymarket.py
  • src/tests/test_polymarket.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/sources/polymarket.py

Comment on lines +567 to 568
@patch("sources.polymarket.time.sleep")
@patch("sources.polymarket.requests.get")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how backoff's sync module performs its sleep call
python -c "import backoff._sync, inspect; print(inspect.getsource(backoff._sync))" 2>/dev/null | grep -n "sleep\|^import\|^from"

Repository: forecastingresearch/forecastbench

Length of output: 171


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== src/tests/test_polymarket.py (around lines 550-590) ==\n'
sed -n '540,600p' src/tests/test_polymarket.py | cat -n

printf '\n== src/sources/polymarket.py (search for _get_market, time, backoff) ==\n'
rg -n "def _get_market|backoff|time\.sleep|import time|requests.get" src/sources/polymarket.py

printf '\n== src/sources/polymarket.py (around _get_market) ==\n'
sed -n '1,220p' src/sources/polymarket.py | cat -n

printf '\n== backoff package sleep implementation (if installed) ==\n'
python3 - <<'PY'
import inspect, sys
try:
    import backoff._sync as s
    print(inspect.getsource(s))
except Exception as e:
    print(type(e).__name__ + ":", e)
    sys.exit(0)
PY

printf '\n== project dependency pins for backoff ==\n'
rg -n "backoff" pyproject.toml requirements*.txt setup.cfg setup.py poetry.lock Pipfile.lock 2>/dev/null || true

Repository: forecastingresearch/forecastbench

Length of output: 14643


🌐 Web query:

backoff _sync.py sleep time.sleep import source GitHub

💡 Result:

In the Python backoff library, the backoff/_sync.py source file manages synchronous retry loops, including the implementation of wait intervals [1][2]. The library uses time.sleep(seconds) to pause execution between retry attempts [2]. When a retry condition is met (e.g., an exception is raised or a predicate is truthy), the library calculates the next wait time and performs a blocking sleep: python # Simplified logic from backoff/_sync.py seconds = _next_wait(wait, e, jitter, elapsed, max_time_value) # ... time.sleep(seconds) Because backoff relies on the standard time.sleep() for its synchronous decorators, you can mock or monkey-patch it during testing if you need to bypass the delays [3]. Common testing patterns include using unittest.mock.patch to intercept backoff._sync.time.sleep [3]. For asynchronous code, backoff handles waiting differently, typically using asyncio.sleep() instead of time.sleep(), as time.sleep() would block the entire event loop [4][5]. You can find the implementation details for asynchronous retries in backoff/_async.py [2].

Citations:


Patch the retry sleep target.
backoff sleeps through its own backoff._sync.time.sleep, so sources.polymarket.time.sleep won’t suppress the retry pause here. Patch backoff._sync.time.sleep (or time.sleep globally) to keep this test fast.

🧰 Tools
🪛 ast-grep (0.44.1)

[info] 567-567: no timeout was given on call to external resource
Context: patch("sources.polymarket.requests.get")
Note: [CWE-1088] Synchronous Access of Remote Resource without Timeout.

(requests-timeout)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tests/test_polymarket.py` around lines 567 - 568, The retry test is
patching the wrong sleep target, so the backoff pause still occurs during
retries. Update the test around the polymarket request retry path to patch
backoff’s actual sleep call via backoff._sync.time.sleep (or patch time.sleep
globally) instead of sources.polymarket.time.sleep, keeping the test fast while
preserving the existing requests.get mock and retry assertions.

@houtanb houtanb force-pushed the polymarket-get-market-backoff branch from 499a593 to 60343bb Compare July 9, 2026 02:07
@houtanb houtanb merged commit 7bd81b1 into forecastingresearch:main Jul 9, 2026
0 of 2 checks passed
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.

2 participants